diff --git a/.editorconfig b/.editorconfig index 4e9988d..15f564e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,10 +7,10 @@ root = true # Default settings ############################################# [*] +end_of_line = lf insert_final_newline = true indent_style = space indent_size = 4 -charset = utf-8 [project.json] indent_size = 2 @@ -183,170 +183,161 @@ csharp_space_between_square_brackets = false dotnet_diagnostic.AvoidAsyncVoid.severity = suggestion ################### -# Microsoft .NET Analyzers (CA) - Design Rules +# Microsoft.CodeAnalysis.NetAnalyzers (CA) ################### +# Design dotnet_diagnostic.CA1000.severity = none # Do not declare static members on generic types — common factory pattern dotnet_diagnostic.CA1001.severity = error # Types that own disposable fields should be disposable dotnet_diagnostic.CA1002.severity = none # Do not expose generic lists — we deliberately expose List; interface-based collections are an older convention we don't follow -dotnet_diagnostic.CA1003.severity = error # Use generic event handler instances -dotnet_diagnostic.CA1005.severity = error # Avoid excessive parameters on generic types +dotnet_diagnostic.CA1003.severity = none # Use generic event handler instances — covered by SST2304 +dotnet_diagnostic.CA1005.severity = none # Avoid excessive parameters on generic types — we deliberately expose 3+ type-parameter types (tuple-style handles, raw engine signals); the ergonomic guidance conflicts with that design dotnet_diagnostic.CA1008.severity = error # Enums should have zero value dotnet_diagnostic.CA1010.severity = none # Collections should implement generic interface — we deliberately expose concrete collection types; interface-based collections are an older convention we don't follow -dotnet_diagnostic.CA1012.severity = error # Abstract types should not have public constructors +dotnet_diagnostic.CA1012.severity = none # Abstract types should not have public constructors — covered by SST1428 dotnet_diagnostic.CA1014.severity = none # Mark assemblies with CLSCompliantAttribute — we don't ship CLS-compliant assemblies dotnet_diagnostic.CA1016.severity = error # Mark assemblies with AssemblyVersionAttribute dotnet_diagnostic.CA1017.severity = none # Mark assemblies with ComVisibleAttribute — we don't ship COM-visible assemblies dotnet_diagnostic.CA1018.severity = error # Mark attributes with AttributeUsageAttribute -dotnet_diagnostic.CA1019.severity = error # Define accessors for attribute arguments +dotnet_diagnostic.CA1019.severity = none # Define accessors for attribute arguments — conflicts with SST2324, which caps an internal attribute's accessor at internal dotnet_diagnostic.CA1021.severity = none # Avoid out parameters - disabled - needed for the zero-allocation idiom in Try/Find APIs and other performance-critical paths dotnet_diagnostic.CA1024.severity = error # Use properties where appropriate dotnet_diagnostic.CA1027.severity = error # Mark enums with FlagsAttribute -dotnet_diagnostic.CA1028.severity = error # Enum storage should be Int32 +dotnet_diagnostic.CA1028.severity = none # Enum storage should be Int32 — covered by SST2313 dotnet_diagnostic.CA1030.severity = none # Use events where appropriate — we use Rx observables instead of CLR events dotnet_diagnostic.CA1031.severity = none # Do not catch general exception types — required at logging/dispose/IO boundaries -dotnet_diagnostic.CA1032.severity = error # Implement standard exception constructors +dotnet_diagnostic.CA1032.severity = none # Implement standard exception constructors — covered by SST1488 dotnet_diagnostic.CA1033.severity = none # Interface methods should be callable by child types — explicit interface implementations are a deliberate design choice dotnet_diagnostic.CA1034.severity = none # Nested types should not be visible — public nested types are sometimes the cleanest API (e.g. interface-scoped exception helpers) dotnet_diagnostic.CA1036.severity = none # Override methods on comparable types — relational operators rarely meaningful for our types -dotnet_diagnostic.CA1040.severity = error # Avoid empty interfaces -dotnet_diagnostic.CA1041.severity = error # Provide ObsoleteAttribute message +dotnet_diagnostic.CA1040.severity = none # Avoid empty interfaces — duplicate of SST1437 (canonical); marker interfaces (IActivatableView etc.) are deliberate public API +dotnet_diagnostic.CA1041.severity = none # Provide ObsoleteAttribute message — covered by SST2308 dotnet_diagnostic.CA1043.severity = error # Use integral or string argument for indexers -dotnet_diagnostic.CA1044.severity = error # Properties should not be write only -dotnet_diagnostic.CA1045.severity = error # Do not pass types by reference +dotnet_diagnostic.CA1044.severity = none # Properties should not be write only — covered by SST1421 +dotnet_diagnostic.CA1045.severity = none # Do not pass types by reference — we deliberately use ref-passing static helpers so they carry only the data they touch; data-oriented layout is the default here dotnet_diagnostic.CA1046.severity = error # Do not overload operator equals on reference types -dotnet_diagnostic.CA1047.severity = error # Do not declare protected member in sealed type -dotnet_diagnostic.CA1048.severity = error # Do not declare virtual members in sealed types -dotnet_diagnostic.CA1050.severity = error # Declare types in namespaces -dotnet_diagnostic.CA1051.severity = error # Do not declare visible instance fields -dotnet_diagnostic.CA1052.severity = error # Static holder types should be sealed -dotnet_diagnostic.CA1053.severity = error # Static holder types should not have constructors +dotnet_diagnostic.CA1047.severity = none # Do not declare protected member in sealed type — covered by SST1427 +dotnet_diagnostic.CA1048.severity = none # Do not declare virtual members in sealed types — covered by SST1491 +dotnet_diagnostic.CA1050.severity = none # Declare types in namespaces — covered by SST2312 +dotnet_diagnostic.CA1051.severity = none # Duplicate of SST1401 (canonical) — do not declare visible instance fields +dotnet_diagnostic.CA1052.severity = none # Static holder types should be sealed — covered by SST1432 +dotnet_diagnostic.CA1053.severity = none # Static holder types should not have constructors — covered by SST1432 dotnet_diagnostic.CA1054.severity = suggestion # URI parameters should not be strings dotnet_diagnostic.CA1055.severity = suggestion # URI return values should not be strings dotnet_diagnostic.CA1056.severity = suggestion # URI properties should not be strings dotnet_diagnostic.CA1058.severity = error # Types should not extend certain base types dotnet_diagnostic.CA1059.severity = error # Members should not expose certain concrete types dotnet_diagnostic.CA1060.severity = error # Move P/Invokes to NativeMethods class -dotnet_diagnostic.CA1061.severity = error # Do not hide base class methods +dotnet_diagnostic.CA1061.severity = none # Do not hide base class methods — covered by SST2427 dotnet_diagnostic.CA1062.severity = none # Validate arguments of public methods - Nullable=enable + we own every consumer, so the compiler already guarantees non-null params -dotnet_diagnostic.CA1063.severity = error # Implement IDisposable correctly +dotnet_diagnostic.CA1063.severity = none # Implement IDisposable correctly — covered by SST2300 dotnet_diagnostic.CA1064.severity = error # Exceptions should be public -dotnet_diagnostic.CA1065.severity = error # Do not raise exceptions in unexpected locations +dotnet_diagnostic.CA1065.severity = none # Do not raise exceptions in unexpected locations — covered by SST1485 dotnet_diagnostic.CA1066.severity = error # Implement IEquatable when overriding Equals dotnet_diagnostic.CA1067.severity = error # Override Equals when implementing IEquatable dotnet_diagnostic.CA1068.severity = error # CancellationToken parameters must come last dotnet_diagnostic.CA1069.severity = error # Enums should not have duplicate values dotnet_diagnostic.CA1070.severity = error # Do not declare event fields as virtual -################### -# Microsoft .NET Analyzers (CA) - Globalization Rules -################### +# Globalization dotnet_diagnostic.CA1303.severity = none # Do not pass literals as localized parameters — we don't ship localized resources +dotnet_diagnostic.CA1307.severity = none # Covered by PSH1207 (canonical) dotnet_diagnostic.CA1308.severity = none # Normalize strings to uppercase — ToLowerInvariant is correct for filesystem path / cache key normalization +dotnet_diagnostic.CA1310.severity = none # Covered by PSH1207 (canonical) -################### -# Microsoft .NET Analyzers (CA) - Interoperability Rules -################### +# Interoperability dotnet_diagnostic.CA1401.severity = error # P/Invokes should not be visible -################### -# Microsoft .NET Analyzers (CA) - Maintainability Rules -################### -dotnet_diagnostic.CA1500.severity = error # Variable names should not match field names -dotnet_diagnostic.CA1501.severity = none # Avoid excessive inheritance — disabled because the analyzer noticeably slows down the build -dotnet_diagnostic.CA1502.severity = none # Avoid excessive complexity — disabled because the analyzer noticeably slows down the build +# Maintainability +dotnet_diagnostic.CA1500.severity = none # Variable names should not match field names — covered by SST1484 +dotnet_diagnostic.CA1501.severity = none # Covered by SST1446 (canonical) +dotnet_diagnostic.CA1502.severity = none # Covered by SST1442 (canonical) dotnet_diagnostic.CA1505.severity = error # Avoid unmaintainable code dotnet_diagnostic.CA1506.severity = none # Avoid excessive class coupling — adds little signal here, mostly trips on legitimate orchestration code -dotnet_diagnostic.CA1507.severity = error # Use nameof in place of string +dotnet_diagnostic.CA1507.severity = none # Use nameof in place of string — covered by SST1463 dotnet_diagnostic.CA1508.severity = error # Avoid dead conditional code dotnet_diagnostic.CA1509.severity = error # Invalid entry in code metrics configuration file -dotnet_diagnostic.CA1510.severity = none # Use ArgumentNullException throw helper — disabled because we target older TFMs and use ArgumentExceptionHelper for cross-platform parity -dotnet_diagnostic.CA1511.severity = none # Use ArgumentException throw helper — disabled because we target older TFMs and use ArgumentExceptionHelper for cross-platform parity -dotnet_diagnostic.CA1512.severity = none # Use ArgumentOutOfRangeException throw helper — disabled because we target older TFMs and use ArgumentExceptionHelper for cross-platform parity -dotnet_diagnostic.CA1513.severity = none # Use ObjectDisposedException throw helper — disabled because we target older TFMs and use ArgumentExceptionHelper for cross-platform parity -dotnet_diagnostic.CA1514.severity = error # Avoid redundant length argument +dotnet_diagnostic.CA1510.severity = none # Covered by PSH1409 (canonical) +dotnet_diagnostic.CA1511.severity = none # Covered by PSH1409 (canonical) +dotnet_diagnostic.CA1512.severity = none # Covered by PSH1409 (canonical) +dotnet_diagnostic.CA1513.severity = none # Covered by PSH1409 (canonical) +dotnet_diagnostic.CA1514.severity = none # Avoid redundant length argument — covered by PSH1220 dotnet_diagnostic.CA1515.severity = none # Consider making public types internal — interferes with tests and reflection-discovered types (BenchmarkDotNet, TUnit, etc.) dotnet_diagnostic.CA1516.severity = error # Use cross-platform intrinsics -################### -# Microsoft .NET Analyzers (CA) - Naming Rules -################### +# Naming dotnet_diagnostic.CA1710.severity = suggestion # Identifiers should have correct suffix dotnet_diagnostic.CA1724.severity = none # Type Names Should Not Match Namespaces — namespace/type name overlap is intentional API surface -################### -# Microsoft .NET Analyzers (CA) - Performance Rules -################### -dotnet_diagnostic.CA1802.severity = error # Use literals where appropriate -dotnet_diagnostic.CA1805.severity = error # Do not initialize unnecessarily +# Performance +dotnet_diagnostic.CA1802.severity = none # Use literals where appropriate — covered by PSH1402 +dotnet_diagnostic.CA1805.severity = none # Do not initialize unnecessarily — covered by PSH1403 dotnet_diagnostic.CA1806.severity = error # Do not ignore method results dotnet_diagnostic.CA1810.severity = none # Initialize reference type static fields inline — explicit static constructors are deliberate in some types dotnet_diagnostic.CA1812.severity = error # Avoid uninstantiated internal classes -dotnet_diagnostic.CA1813.severity = error # Avoid unsealed attributes -dotnet_diagnostic.CA1814.severity = error # Prefer jagged arrays over multidimensional -dotnet_diagnostic.CA1815.severity = error # Override equals and operator equals on value types +dotnet_diagnostic.CA1813.severity = none # Avoid unsealed attributes — covered by PSH1401 +dotnet_diagnostic.CA1814.severity = none # Prefer jagged arrays over multidimensional — covered by PSH1020 +dotnet_diagnostic.CA1815.severity = none # Override equals and operator equals on value types — covered by PSH1005 dotnet_diagnostic.CA1819.severity = none # Properties should not return arrays — incompatible with the RxUI/sqlite-net mapping style we use throughout the codebase -dotnet_diagnostic.CA1820.severity = error # Test for empty strings using string length -dotnet_diagnostic.CA1821.severity = error # Remove empty finalizers -dotnet_diagnostic.CA1822.severity = error # Mark members as static -dotnet_diagnostic.CA1823.severity = error # Avoid unused private fields +dotnet_diagnostic.CA1820.severity = none # Test for empty strings using string length — covered by PSH1204 +dotnet_diagnostic.CA1821.severity = none # Remove empty finalizers — covered by PSH1002 +dotnet_diagnostic.CA1822.severity = none # Mark members as static — covered by PSH1414 +dotnet_diagnostic.CA1823.severity = none # Avoid unused private fields — covered by SST1441 dotnet_diagnostic.CA1824.severity = error # Mark assemblies with NeutralResourcesLanguageAttribute -dotnet_diagnostic.CA1825.severity = error # Avoid zero-length array allocations -dotnet_diagnostic.CA1826.severity = error # Use property instead of Linq Enumerable method -dotnet_diagnostic.CA1827.severity = error # Do not use Count/LongCount when Any can be used -dotnet_diagnostic.CA1828.severity = error # Do not use CountAsync/LongCountAsync when AnyAsync can be used -dotnet_diagnostic.CA1829.severity = error # Use Length/Count property instead of Enumerable.Count method -dotnet_diagnostic.CA1830.severity = error # Prefer strongly-typed Append and Insert method overloads on StringBuilder -dotnet_diagnostic.CA1831.severity = error # Use AsSpan instead of Range-based indexers for string when appropriate -dotnet_diagnostic.CA1832.severity = error # Use AsSpan or AsMemory instead of Range-based indexers for getting ReadOnlySpan or ReadOnlyMemory portion of an array -dotnet_diagnostic.CA1833.severity = error # Use AsSpan or AsMemory instead of Range-based indexers for getting Span or Memory portion of an array -dotnet_diagnostic.CA1834.severity = error # Use StringBuilder.Append(char) for single character strings -dotnet_diagnostic.CA1835.severity = error # Prefer the memory-based overloads of ReadAsync/WriteAsync methods in stream-based classes -dotnet_diagnostic.CA1836.severity = error # Prefer IsEmpty over Count when available -dotnet_diagnostic.CA1837.severity = error # Use Environment.ProcessId instead of Process.GetCurrentProcess().Id +dotnet_diagnostic.CA1825.severity = none # Avoid zero-length array allocations — covered by PSH1001 +dotnet_diagnostic.CA1826.severity = none # Use property instead of Linq Enumerable method — covered by PSH1103 +dotnet_diagnostic.CA1827.severity = none # Do not use Count/LongCount when Any can be used — covered by PSH1119 +dotnet_diagnostic.CA1828.severity = none # Do not use CountAsync/LongCountAsync when AnyAsync can be used — covered by PSH1126 +dotnet_diagnostic.CA1829.severity = none # Use Length/Count property instead of Enumerable.Count — covered by PSH1103 +dotnet_diagnostic.CA1830.severity = none # Prefer strongly-typed Append/Insert overloads on StringBuilder — covered by PSH1202 +dotnet_diagnostic.CA1831.severity = none # Use AsSpan instead of Range-based indexers for string — covered by PSH1212 +dotnet_diagnostic.CA1832.severity = none # Use AsSpan or AsMemory instead of Range-based indexers for getting ReadOnlySpan or ReadOnlyMemory portion of an array — covered by PSH1019 +dotnet_diagnostic.CA1833.severity = none # Use AsSpan or AsMemory instead of Range-based indexers for getting Span or Memory portion of an array — conflicts with PSH1019, which owns the array range-indexer rewrite and refuses it for mutable Span/Memory targets +dotnet_diagnostic.CA1834.severity = none # Use StringBuilder.Append(char) for single character strings — covered by PSH1202 +dotnet_diagnostic.CA1835.severity = none # Prefer the memory-based overloads of ReadAsync/WriteAsync methods in stream-based classes — covered by PSH1314 +dotnet_diagnostic.CA1836.severity = none # Prefer IsEmpty over Count when available — covered by PSH1117 +dotnet_diagnostic.CA1837.severity = none # Use Environment.ProcessId — covered by PSH1405 dotnet_diagnostic.CA1838.severity = error # Avoid StringBuilder parameters for P/Invokes -dotnet_diagnostic.CA1839.severity = error # Use Environment.ProcessPath instead of Process.GetCurrentProcess().MainModule.FileName -dotnet_diagnostic.CA1840.severity = error # Use Environment.CurrentManagedThreadId instead of Thread.CurrentThread.ManagedThreadId -dotnet_diagnostic.CA1841.severity = error # Prefer Dictionary.Contains methods -dotnet_diagnostic.CA1842.severity = error # Do not use 'WhenAll' with a single task -dotnet_diagnostic.CA1843.severity = error # Do not use 'WaitAll' with a single task +dotnet_diagnostic.CA1839.severity = none # Use Environment.ProcessPath — covered by PSH1405 +dotnet_diagnostic.CA1840.severity = none # Use Environment.CurrentManagedThreadId — covered by PSH1405 +dotnet_diagnostic.CA1841.severity = none # Prefer Dictionary.Contains methods — covered by PSH1407 +dotnet_diagnostic.CA1842.severity = none # Do not use 'WhenAll' with a single task — covered by PSH1301 +dotnet_diagnostic.CA1843.severity = none # Do not use 'WaitAll' with a single task — covered by PSH1301 dotnet_diagnostic.CA1844.severity = error # Provide memory-based overrides of async methods when subclassing 'Stream' -dotnet_diagnostic.CA1845.severity = error # Use span-based 'string.Concat' -dotnet_diagnostic.CA1846.severity = error # Prefer AsSpan over Substring -dotnet_diagnostic.CA1847.severity = none # Use char literal for a single character lookup — disabled because the string.Contains(char) overload doesn't exist on .NET Framework / netstandard2.0 and we target both +dotnet_diagnostic.CA1845.severity = none # Use span-based 'string.Concat' — covered by PSH1222 +dotnet_diagnostic.CA1846.severity = none # Prefer AsSpan over Substring — covered by PSH1212 +dotnet_diagnostic.CA1847.severity = none # Covered by PSH1201 (canonical) dotnet_diagnostic.CA1848.severity = error # Use the LoggerMessage delegates -dotnet_diagnostic.CA1849.severity = error # Call async methods when in an async method -dotnet_diagnostic.CA1850.severity = error # Prefer static HashData method over ComputeHash +dotnet_diagnostic.CA1849.severity = none # Call async methods when in an async method — covered by PSH1313 +dotnet_diagnostic.CA1850.severity = none # Prefer static HashData method over ComputeHash — covered by PSH1400 dotnet_diagnostic.CA1851.severity = error # Possible multiple enumerations of IEnumerable collection -dotnet_diagnostic.CA1852.severity = error # Seal internal types +dotnet_diagnostic.CA1852.severity = none # Seal internal types — covered by PSH1411 dotnet_code_quality.CA1852.api_surface = private, internal # only flag non-public classes; public classes stay open for inheritance -dotnet_diagnostic.CA1853.severity = error # Unnecessary call to 'Dictionary.ContainsKey(key)' -dotnet_diagnostic.CA1854.severity = error # Prefer the IDictionary.TryGetValue(TKey, out TValue) method +dotnet_diagnostic.CA1853.severity = none # Unnecessary call to 'Dictionary.ContainsKey(key)' — covered by PSH1105 +dotnet_diagnostic.CA1854.severity = none # Prefer the IDictionary.TryGetValue method — covered by PSH1104 dotnet_diagnostic.CA1855.severity = error # Prefer 'Clear' over 'Fill' dotnet_diagnostic.CA1856.severity = error # Incorrect usage of ConstantExpected attribute dotnet_diagnostic.CA1857.severity = error # A constant is expected for the parameter -dotnet_diagnostic.CA1858.severity = error # Use 'StartsWith' instead of 'IndexOf' +dotnet_diagnostic.CA1858.severity = none # Use 'StartsWith' instead of 'IndexOf' — covered by PSH1221 dotnet_diagnostic.CA1859.severity = error # Use concrete types when possible for improved performance -dotnet_diagnostic.CA1860.severity = error # Avoid using 'Enumerable.Any()' extension method -dotnet_diagnostic.CA1861.severity = error # Avoid constant arrays as arguments -dotnet_diagnostic.CA1862.severity = error # Use the 'StringComparison' method overloads to perform case-insensitive string comparisons -dotnet_diagnostic.CA1863.severity = error # Use 'CompositeFormat' -dotnet_diagnostic.CA1864.severity = error # Prefer the 'IDictionary.TryAdd(TKey, TValue)' method -dotnet_diagnostic.CA1865.severity = none # Use char overload (string.StartsWith) — disabled because the string.StartsWith(char) overload doesn't exist on .NET Framework / netstandard2.0 and we target both -dotnet_diagnostic.CA1866.severity = none # Use char overload (string.EndsWith) — disabled because the string.EndsWith(char) overload doesn't exist on .NET Framework / netstandard2.0 and we target both -dotnet_diagnostic.CA1867.severity = none # Use char overload (string.IndexOf / string.LastIndexOf) — disabled because the char overloads don't exist on .NET Framework / netstandard2.0 and we target both -dotnet_diagnostic.CA1868.severity = error # Unnecessary call to 'Contains' for sets -dotnet_diagnostic.CA1869.severity = error # Cache and reuse 'JsonSerializerOptions' instances -dotnet_diagnostic.CA1870.severity = error # Use a cached 'SearchValues' instance +dotnet_diagnostic.CA1860.severity = none # Avoid using 'Enumerable.Any()' extension method — covered by PSH1103 +dotnet_diagnostic.CA1861.severity = none # Avoid constant arrays as arguments — covered by PSH1004 +dotnet_diagnostic.CA1862.severity = none # Use the 'StringComparison' overloads for case-insensitive comparisons — covered by PSH1200 +dotnet_diagnostic.CA1863.severity = none # Use 'CompositeFormat' — covered by PSH1223 +dotnet_diagnostic.CA1864.severity = none # Prefer the 'IDictionary.TryAdd' method — covered by PSH1115 +dotnet_diagnostic.CA1865.severity = none # Covered by PSH1201 (canonical) +dotnet_diagnostic.CA1866.severity = none # Covered by PSH1201 (canonical) +dotnet_diagnostic.CA1867.severity = none # Covered by PSH1201 (canonical) +dotnet_diagnostic.CA1868.severity = none # Unnecessary call to 'Contains' for sets — covered by PSH1105 +dotnet_diagnostic.CA1869.severity = none # Cache and reuse 'JsonSerializerOptions' instances — covered by PSH1416 +dotnet_diagnostic.CA1870.severity = none # Use a cached 'SearchValues' instance — covered by PSH1213 dotnet_diagnostic.CA1871.severity = error # Do not pass a nullable struct to 'ArgumentNullException.ThrowIfNull' -dotnet_diagnostic.CA1872.severity = error # Prefer 'Convert.ToHexString' and 'Convert.ToHexStringLower' over call chains based on 'BitConverter.ToString' -dotnet_diagnostic.CA1873.severity = error # Avoid potentially expensive evaluation of arguments to 'Debug.Assert' -dotnet_diagnostic.CA1874.severity = error # Use 'Regex.IsMatch' -dotnet_diagnostic.CA1875.severity = error # Use 'Regex.Count' -dotnet_diagnostic.CA1877.severity = error # Use 'Encoding.GetString' instead of 'Encoding.GetChars' +dotnet_diagnostic.CA1872.severity = none # Prefer 'Convert.ToHexString' and 'Convert.ToHexStringLower' over call chains based on 'BitConverter.ToString' — covered by PSH1224 +dotnet_diagnostic.CA1873.severity = none # Avoid potentially expensive evaluation of arguments to 'Debug.Assert' — covered by PSH1417 +dotnet_diagnostic.CA1874.severity = none # Use 'Regex.IsMatch' — covered by PSH1406 +dotnet_diagnostic.CA1875.severity = none # Use 'Regex.Count' — covered by PSH1406 +dotnet_diagnostic.CA1877.severity = none # Use 'Encoding.GetString' instead of 'Encoding.GetChars' — covered by PSH1225 -################### -# Microsoft .NET Analyzers (CA) - Reliability Rules -################### +# Reliability dotnet_diagnostic.CA2000.severity = suggestion # Dispose objects before losing scope dotnet_diagnostic.CA2002.severity = error # Do not lock on objects with weak identity dotnet_diagnostic.CA2007.severity = none # Do not directly await a Task — Rx and library callers drive synchronization context themselves @@ -369,41 +360,39 @@ dotnet_diagnostic.CA2024.severity = error # Do not use 'StreamReader.EndOfStream dotnet_diagnostic.CA2025.severity = error # Do not pass 'IDisposable' instances into unawaited tasks dotnet_diagnostic.CA2026.severity = error # Do not use methods or types annotated with [RequiresDynamicCode] in code that uses [RequiresDynamicCode] -################### -# Microsoft .NET Analyzers (CA) - Usage Rules -################### +# Usage dotnet_diagnostic.CA1801.severity = error # Review unused parameters dotnet_code_quality.CA1801.api_surface = private, internal # only flag non-public APIs so we don't break public signatures dotnet_diagnostic.CA1816.severity = error # Call GC.SuppressFinalize correctly -dotnet_diagnostic.CA2200.severity = error # Rethrow to preserve stack details +dotnet_diagnostic.CA2200.severity = none # Rethrow to preserve stack details — covered by SST1430 dotnet_diagnostic.CA2201.severity = error # Do not raise reserved exception types dotnet_diagnostic.CA2207.severity = error # Initialize value type static fields inline dotnet_diagnostic.CA2208.severity = none # Instantiate argument exceptions correctly — too sensitive: flags valid context-forwarding nameof(arg.Property) patterns -dotnet_diagnostic.CA2211.severity = error # Non-constant fields should not be visible +dotnet_diagnostic.CA2211.severity = none # Non-constant fields should not be visible — covered by SST1499 dotnet_diagnostic.CA2213.severity = error # Disposable fields should be disposed -dotnet_diagnostic.CA2214.severity = error # Do not call overridable methods in constructors +dotnet_diagnostic.CA2214.severity = none # Do not call overridable methods in constructors — covered by SST1483 dotnet_diagnostic.CA2215.severity = error # Dispose methods should call base class dispose -dotnet_diagnostic.CA2216.severity = error # Disposable types should declare finalizer -dotnet_diagnostic.CA2217.severity = error # Do not mark enums with FlagsAttribute +dotnet_diagnostic.CA2216.severity = none # Disposable types should declare finalizer — conflicts with SST2317, which owns the owned-native-handle shape and prescribes a SafeHandle instead of a finalizer +dotnet_diagnostic.CA2217.severity = none # Do not mark enums with FlagsAttribute — covered by SST2303 dotnet_diagnostic.CA2218.severity = error # Override GetHashCode on overriding Equals dotnet_diagnostic.CA2219.severity = error # Do not raise exceptions in finally clauses -dotnet_diagnostic.CA2224.severity = error # Override Equals on overloading operator equals +dotnet_diagnostic.CA2224.severity = none # Override Equals on overloading operator equals — covered by SST2302 dotnet_diagnostic.CA2225.severity = error # Operator overloads have named alternates dotnet_diagnostic.CA2226.severity = error # Operators should have symmetrical overloads dotnet_diagnostic.CA2227.severity = none # Collection properties should be read only — settable collection properties are common in our DTOs and config types dotnet_diagnostic.CA2231.severity = error # Overload operator equals on overriding ValueType.Equals dotnet_diagnostic.CA2234.severity = error # Pass System.Uri objects instead of strings dotnet_diagnostic.CA2241.severity = error # Provide correct arguments to formatting methods -dotnet_diagnostic.CA2242.severity = error # Test for NaN correctly +dotnet_diagnostic.CA2242.severity = none # Test for NaN correctly — covered by SST1473 dotnet_diagnostic.CA2243.severity = error # Attribute string literals should parse correctly dotnet_diagnostic.CA2244.severity = error # Do not duplicate indexed element initializations -dotnet_diagnostic.CA2245.severity = error # Do not assign a property to itself +dotnet_diagnostic.CA2245.severity = none # Do not assign a property to itself — covered by SST1189 dotnet_diagnostic.CA2246.severity = error # Do not assign a symbol and its member in the same statement dotnet_diagnostic.CA2247.severity = error # Argument passed to TaskCompletionSource constructor should be TaskCreationOptions enum dotnet_diagnostic.CA2248.severity = error # Provide correct enum argument to Enum.HasFlag dotnet_diagnostic.CA2249.severity = error # Use String.Contains instead of String.IndexOf for substring checks dotnet_diagnostic.CA2250.severity = error # Use ThrowIfCancellationRequested -dotnet_diagnostic.CA2251.severity = error # Use String.Equals over String.Compare +dotnet_diagnostic.CA2251.severity = none # Covered by PSH1216 (canonical) dotnet_diagnostic.CA2252.severity = error # Opt in to preview features before using them dotnet_diagnostic.CA2253.severity = error # Named placeholders should not be numeric values dotnet_diagnostic.CA2254.severity = error # Template should be a static expression @@ -424,9 +413,7 @@ dotnet_diagnostic.CA2268.severity = error # Use 'string.Equals(string, string, S # Skipped (deprecated ISerializable formatter): CA2229 Implement serialization constructors, # CA2235 Mark all non-serializable fields, CA2237 Mark ISerializable types with SerializableAttribute. -################### -# Microsoft .NET Analyzers (CA) - Security Rules -################### +# Security # SQL Injection & Command Injection dotnet_diagnostic.CA2100.severity = error # Review SQL queries for security vulnerabilities @@ -549,15 +536,9 @@ dotnet_diagnostic.CA2153.severity = error # Do not catch corrupted state excepti dotnet_diagnostic.CA5367.severity = error # Do not serialize types with pointer fields ################### -# SonarAnalyzer (Sxxxx) — global suppressions -################### -dotnet_diagnostic.S1075.severity = none # Hardcoded URI — canonical SourceLink hosts are the point -dotnet_diagnostic.S2436.severity = none # Too many generic parameters — needed for the projector overload -dotnet_diagnostic.S4036.severity = none # PATH-relative process spawn — benchmark only, trusted env - -################### -# Microsoft .NET Runtime Obsoletions (SYSLIB0xxx) +# Microsoft .NET SDK Diagnostics (SYSLIB) ################### +# Runtime obsoletions dotnet_diagnostic.SYSLIB0001.severity = error # The UTF-7 encoding is insecure and should not be used dotnet_diagnostic.SYSLIB0002.severity = error # PrincipalPermissionAttribute is not honored by the runtime and must not be used dotnet_diagnostic.SYSLIB0003.severity = error # Code Access Security (CAS) is not supported or honored by the runtime @@ -620,9 +601,7 @@ dotnet_diagnostic.SYSLIB0059.severity = error # SystemEvents.EventsThreadShutdow dotnet_diagnostic.SYSLIB0060.severity = error # Constructors of DirectoryServices.ActiveDirectory.ConfigurationContext are obsolete dotnet_diagnostic.SYSLIB0061.severity = error # CryptographyConfig.AddOID and AddAlgorithm methods are obsolete -################### -# Microsoft .NET Source Generator Diagnostics (SYSLIB1xxx) -################### +# Source generators # LoggerMessage source generator dotnet_diagnostic.SYSLIB1001.severity = error # Logging method names cannot start with _ dotnet_diagnostic.SYSLIB1002.severity = error # Don't include log level parameters as templates in the logging message @@ -710,8 +689,9 @@ dotnet_diagnostic.SYSLIB1103.severity = error # Configuration binding source gen dotnet_diagnostic.SYSLIB1104.severity = error # Configuration binding source generator: language version is too low ################### -# Microsoft .NET Style Rules (IDExxxx) - Language Rules +# Microsoft .NET Code Style Analyzers (IDE) ################### +# Language rules # EnforceCodeStyleInBuild=true (set in Directory.Build.props) promotes these # IDE rules into `dotnet build` so they fire at compile time, not just in the # IDE. We enable the ones that are unambiguous wins and skip the rules that @@ -719,124 +699,128 @@ dotnet_diagnostic.SYSLIB1104.severity = error # Configuration binding source gen # etc.) so we don't double-report. # Bug catchers — always error. -dotnet_diagnostic.IDE0035.severity = error # Remove unreachable code -dotnet_diagnostic.IDE0043.severity = error # Format string contains invalid placeholder -dotnet_diagnostic.IDE0051.severity = error # Remove unused private member -dotnet_diagnostic.IDE0052.severity = error # Remove unread private member -dotnet_diagnostic.IDE0076.severity = error # Remove invalid global SuppressMessage attribute -dotnet_diagnostic.IDE0077.severity = error # Avoid legacy format target in global SuppressMessage attribute -dotnet_diagnostic.IDE0080.severity = error # Remove unnecessary suppression operator +dotnet_diagnostic.IDE0035.severity = none # Remove unreachable code — covered by SST1453 +dotnet_diagnostic.IDE0043.severity = none # Format string contains invalid placeholder — covered by SST1454 +dotnet_diagnostic.IDE0052.severity = none # Remove unread private member — covered by SST1441 # Simplification / cleanup. -dotnet_diagnostic.IDE0001.severity = error # Simplify name -dotnet_diagnostic.IDE0002.severity = error # Simplify member access -dotnet_diagnostic.IDE0004.severity = none # Remove unnecessary cast — disabled because we deliberately keep explicit casts in Apple platform-specific paths and other reflection/marshalling sites where the analyzer's "redundant" judgement is wrong -dotnet_diagnostic.IDE0005.severity = none # Remove unnecessary import - DUPLICATE S1128 (slower: 2.364s vs 551ms) -dotnet_diagnostic.IDE0016.severity = error # Use throw expression -dotnet_diagnostic.IDE0017.severity = error # Use object initializers -dotnet_diagnostic.IDE0018.severity = error # Inline variable declaration -dotnet_diagnostic.IDE0019.severity = error # Use pattern matching to avoid 'as' followed by a 'null' check -dotnet_diagnostic.IDE0020.severity = error # Use pattern matching to avoid 'is' check followed by a cast -dotnet_diagnostic.IDE0028.severity = error # Use collection initializers -dotnet_diagnostic.IDE0029.severity = none # Use coalesce expression — handled by RCS1128 -dotnet_diagnostic.IDE0030.severity = error # Use coalesce expression (nullable types) -dotnet_diagnostic.IDE0031.severity = none # Use null propagation — handled by RCS1146 -dotnet_diagnostic.IDE0032.severity = none # Use auto property — handled by RCS1085 -dotnet_diagnostic.IDE0033.severity = error # Use explicitly provided tuple name -dotnet_diagnostic.IDE0034.severity = error # Simplify default expression -dotnet_diagnostic.IDE0037.severity = error # Use inferred member name -dotnet_diagnostic.IDE0038.severity = error # Use pattern matching ('is' check without a cast) -dotnet_diagnostic.IDE0041.severity = error # Use 'is null' check -dotnet_diagnostic.IDE0042.severity = error # Deconstruct variable declaration -dotnet_diagnostic.IDE0044.severity = error # Add readonly modifier -dotnet_diagnostic.IDE0046.severity = suggestion # Use conditional expression for return — downgraded because nested coalescing/ternary chains it produces hurt readability -dotnet_diagnostic.IDE0047.severity = error # Remove unnecessary parentheses -dotnet_diagnostic.IDE0049.severity = error # Use language keywords instead of framework type names for type references -dotnet_diagnostic.IDE0054.severity = error # Use compound assignment -dotnet_diagnostic.IDE0056.severity = suggestion # Use index operator -dotnet_diagnostic.IDE0057.severity = suggestion # Use range operator -dotnet_diagnostic.IDE0059.severity = error # Remove unnecessary value assignment -dotnet_diagnostic.IDE0062.severity = error # Make local function static -dotnet_diagnostic.IDE0063.severity = error # Use simple 'using' statement -dotnet_diagnostic.IDE0064.severity = error # Make struct fields writable — flag readonly-but-mutable struct fields where intent diverges from declaration -dotnet_diagnostic.IDE0066.severity = error # Use switch expression -dotnet_diagnostic.IDE0070.severity = error # Use 'System.HashCode.Combine' -dotnet_diagnostic.IDE0071.severity = error # Simplify interpolation -dotnet_diagnostic.IDE0072.severity = suggestion # Add missing cases to switch expression - sometimes we miss switch cases dilberately. -dotnet_diagnostic.IDE0074.severity = error # Use compound assignment -dotnet_diagnostic.IDE0075.severity = error # Simplify conditional expression -dotnet_diagnostic.IDE0078.severity = error # Use pattern matching -dotnet_diagnostic.IDE0082.severity = error # Convert typeof to nameof -dotnet_diagnostic.IDE0083.severity = error # Use pattern matching ('not' operator) -dotnet_diagnostic.IDE0084.severity = error # Use pattern matching ('IsNot' operator) -dotnet_diagnostic.IDE0090.severity = error # Simplify 'new' expression -dotnet_diagnostic.IDE0100.severity = error # Remove unnecessary equality operator -dotnet_diagnostic.IDE0110.severity = error # Remove unnecessary discard -dotnet_diagnostic.IDE0120.severity = error # Simplify LINQ expression -dotnet_diagnostic.IDE0150.severity = error # Prefer 'null' check over type check -dotnet_diagnostic.IDE0161.severity = error # Use file-scoped namespace declaration -dotnet_diagnostic.IDE0170.severity = error # Simplify property pattern -dotnet_diagnostic.IDE0180.severity = error # Use tuple to swap values -dotnet_diagnostic.IDE0200.severity = error # Remove unnecessary lambda expression -dotnet_diagnostic.IDE0220.severity = error # Add explicit cast in foreach loop -dotnet_diagnostic.IDE0240.severity = error # Remove redundant nullable directive -dotnet_diagnostic.IDE0241.severity = error # Remove unnecessary nullable directive -dotnet_diagnostic.IDE0250.severity = error # Make struct 'readonly' -dotnet_diagnostic.IDE0251.severity = error # Make member 'readonly' -dotnet_diagnostic.IDE0260.severity = error # Use pattern matching -dotnet_diagnostic.IDE0270.severity = error # Use coalesce expression +dotnet_diagnostic.IDE0002.severity = none # Simplify member access — covered by SST1117 +dotnet_diagnostic.IDE0004.severity = none # Remove unnecessary cast — covered by SST1175 +dotnet_diagnostic.IDE0016.severity = none # Use throw expression — covered by SST2207 +dotnet_diagnostic.IDE0019.severity = none # Use pattern matching to avoid 'as' followed by a 'null' check — covered by SST2005/SST2274 +dotnet_diagnostic.IDE0028.severity = none # Use collection initializers — covered by SST1194 +dotnet_diagnostic.IDE0031.severity = none # Use null propagation — covered by SST1196 +dotnet_diagnostic.IDE0038.severity = none # Use pattern matching ('is' check without a cast) — covered by SST2007 +dotnet_diagnostic.IDE0041.severity = none # Use 'is null' check — covered by SST1149/SST2231/SST2282 +dotnet_diagnostic.IDE0042.severity = none # Deconstruct variable declaration — covered by SST2214 +dotnet_diagnostic.IDE0044.severity = none # Add readonly modifier — covered by SST1424 +dotnet_diagnostic.IDE0047.severity = none # Remove unnecessary parentheses — covered by SST1459 +dotnet_diagnostic.IDE0049.severity = none # Use language keywords instead of framework type names for type references — covered by SST1121 +dotnet_diagnostic.IDE0057.severity = none # Use range operator — covered by SST2204 +dotnet_diagnostic.IDE0059.severity = none # Remove unnecessary value assignment — covered by SST2222 +dotnet_diagnostic.IDE0064.severity = none # Make struct fields writable — flag readonly-but-mutable struct fields where intent diverges from declaration +dotnet_diagnostic.IDE0066.severity = none # Use switch expression — covered by SST2201 +dotnet_diagnostic.IDE0075.severity = none # Simplify conditional expression — covered by SST1182 +dotnet_diagnostic.IDE0078.severity = none # Use pattern matching — covered by SST2006/SST2231 +dotnet_diagnostic.IDE0084.severity = none # Use pattern matching ('IsNot' operator) +dotnet_diagnostic.IDE0120.severity = none # Simplify LINQ expression — covered by PSH1100/PSH1101 +dotnet_diagnostic.IDE0221.severity = none # Add explicit cast — covered by SST2226 +dotnet_diagnostic.IDE0250.severity = none # Make struct 'readonly' — covered by PSH1014 +dotnet_diagnostic.IDE0260.severity = none # Use pattern matching — covered by SST2006/SST2231 # Disabled — conflict with an existing SA/CA rule or project convention. -dotnet_diagnostic.IDE0003.severity = none # Remove 'this' qualifier — we don't follow the this. prefix style (SA1101 = none) dotnet_diagnostic.IDE0007.severity = none # Use var — we don't force var in either direction dotnet_diagnostic.IDE0008.severity = none # Use explicit type — we don't force var in either direction dotnet_diagnostic.IDE0009.severity = none # Member access should be qualified — SA1101 = none -dotnet_diagnostic.IDE0010.severity = none # Add missing cases to switch statement — too noisy for default/fallthrough patterns -dotnet_diagnostic.IDE0011.severity = none # Add braces — RCS1001 / RCS1007 already handle this -dotnet_diagnostic.IDE0021.severity = none # Use expression body for constructors — preference not enforced -dotnet_diagnostic.IDE0022.severity = none # Use expression body for methods — preference not enforced -dotnet_diagnostic.IDE0023.severity = none # Use expression body for conversion operators — preference not enforced -dotnet_diagnostic.IDE0024.severity = none # Use expression body for operators — preference not enforced -dotnet_diagnostic.IDE0025.severity = none # Use expression body for properties — preference not enforced -dotnet_diagnostic.IDE0026.severity = none # Use expression body for indexers — preference not enforced -dotnet_diagnostic.IDE0027.severity = none # Use expression body for accessors — preference not enforced -dotnet_diagnostic.IDE0036.severity = none # Order modifiers — SA1206 handles -dotnet_diagnostic.IDE0039.severity = none # Use local function — anonymous method preference not enforced -dotnet_diagnostic.IDE0040.severity = none # Add accessibility modifiers — SA1400 handles -dotnet_diagnostic.IDE0045.severity = none # Use conditional expression for assignment — preference not enforced +dotnet_diagnostic.IDE0021.severity = none # Use expression body for constructors — covered by SST2276 (opt-in) +dotnet_diagnostic.IDE0022.severity = none # Use expression body for methods — covered by SST2275 +dotnet_diagnostic.IDE0023.severity = none # Use expression body for conversion operators — covered by SST2278 (opt-in) +dotnet_diagnostic.IDE0024.severity = none # Use expression body for operators — covered by SST2277 (opt-in) +dotnet_diagnostic.IDE0025.severity = none # Use expression body for properties — covered by SST2279 +dotnet_diagnostic.IDE0026.severity = none # Use expression body for indexers — covered by SST2280 dotnet_diagnostic.IDE0048.severity = none # Add parentheses for clarity — preference not enforced -dotnet_diagnostic.IDE0053.severity = none # Use expression body for lambdas — preference not enforced dotnet_diagnostic.IDE0055.severity = none # Formatting — StyleCop SA rules own formatting -dotnet_diagnostic.IDE0058.severity = none # Remove unnecessary expression value — too noisy (ignores fluent APIs) +dotnet_diagnostic.IDE0058.severity = none # Remove unnecessary expression value — covered by SST2221 dotnet_diagnostic.IDE0060.severity = none # Remove unused parameter — CA1801 handles (with api_surface config) -dotnet_diagnostic.IDE0061.severity = none # Use expression body for local function — preference not enforced -dotnet_diagnostic.IDE0065.severity = none # 'using' directive placement — SA1200 = none (we put usings outside file-scoped namespaces) -dotnet_diagnostic.IDE0073.severity = none # Require file header — SA1633 handles +dotnet_diagnostic.IDE0061.severity = none # Use expression body for local function — covered by SST2281 dotnet_diagnostic.IDE0079.severity = none # Remove unnecessary suppression — can misfire on multi-TFM suppressions dotnet_diagnostic.IDE0130.severity = none # Namespace does not match folder structure — we don't enforce strict mirror dotnet_diagnostic.IDE0160.severity = none # Use block-scoped namespace — we use file-scoped (IDE0161) dotnet_diagnostic.IDE0210.severity = none # Convert to top-level statements — we use Main style dotnet_diagnostic.IDE0211.severity = none # Convert to 'Program.Main' style — we use Main style -dotnet_diagnostic.IDE0280.severity = none # Use nameof — CA1507 / RCS1015 handle this -dotnet_diagnostic.IDE0290.severity = none # Use primary constructor — subjective, not enforced -dotnet_diagnostic.IDE0300.severity = error # Use collection expression for array -dotnet_diagnostic.IDE0301.severity = error # Use collection expression for empty -dotnet_diagnostic.IDE0302.severity = error # Use collection expression for stackalloc -dotnet_diagnostic.IDE0303.severity = error # Use collection expression for Create -dotnet_diagnostic.IDE0304.severity = error # Use collection expression for builder -dotnet_diagnostic.IDE0305.severity = error # Use collection expression for fluent -dotnet_diagnostic.IDE0306.severity = error # Use collection expression for new -dotnet_diagnostic.IDE0320.severity = error # Make anonymous function static — eliminates the closure-capture display class allocation -dotnet_diagnostic.IDE0050.severity = error # Convert anonymous type to tuple -dotnet_diagnostic.IDE0230.severity = error # Use UTF-8 string literal — better hot-path encoding for byte-array constants +dotnet_diagnostic.IDE0300.severity = none # Use collection expression for array — covered by SST2101 +dotnet_diagnostic.IDE0306.severity = none # Use collection expression for new — covered by SST2101 +dotnet_diagnostic.IDE0320.severity = none # Make anonymous function static — covered by PSH1000 +dotnet_diagnostic.IDE0050.severity = none # Convert anonymous type to tuple — covered by SST2224 dotnet_diagnostic.IDE0310.severity = none # Convert lambda expression to method group — handled by RCS1207 +dotnet_diagnostic.IDE0360.severity = none # Simplify property accessor — covered by SST2219 dotnet_diagnostic.IDE0370.severity = none # Remove unnecessary suppression (null-forgiving operator) — disabled for the same reason as RCS1249: multi-TFM nullability annotations can differ per platform -dotnet_diagnostic.IDE0380.severity = error # Remove unnecessary unsafe modifier -dotnet_diagnostic.IDE1005.severity = error # Use conditional delegate call -################### -# Microsoft .NET Style Rules (IDE1xxx / IDE3xxx) - Naming & Miscellaneous -################### +# Language and unnecessary code rules. +dotnet_diagnostic.IDE0001.severity = none # Simplify name +dotnet_diagnostic.IDE0003.severity = none # Name can be simplified +dotnet_diagnostic.IDE0005.severity = none # Remove unnecessary import +dotnet_diagnostic.IDE0010.severity = none # Add missing cases to switch statement +dotnet_diagnostic.IDE0011.severity = none # Add braces +dotnet_diagnostic.IDE0017.severity = none # Use object initializers +dotnet_diagnostic.IDE0018.severity = none # Inline variable declaration +dotnet_diagnostic.IDE0020.severity = none # Use pattern matching to avoid is check followed by a cast (with variable) +dotnet_diagnostic.IDE0027.severity = none # Use expression body for accessors +dotnet_diagnostic.IDE0029.severity = none # Null check can be simplified +dotnet_diagnostic.IDE0030.severity = none # Null check can be simplified +dotnet_diagnostic.IDE0032.severity = none # Use auto property +dotnet_diagnostic.IDE0033.severity = none # Use explicitly provided tuple name +dotnet_diagnostic.IDE0034.severity = none # Simplify default expression +dotnet_diagnostic.IDE0036.severity = none # Order modifiers +dotnet_diagnostic.IDE0037.severity = none # Use inferred member name +dotnet_diagnostic.IDE0039.severity = none # Use local function instead of lambda +dotnet_diagnostic.IDE0040.severity = none # Add accessibility modifiers +dotnet_diagnostic.IDE0045.severity = none # Use conditional expression for assignment +dotnet_diagnostic.IDE0046.severity = none # Use conditional expression for return +dotnet_diagnostic.IDE0051.severity = none # Remove unused private member +dotnet_diagnostic.IDE0053.severity = none # Use expression body for lambdas +dotnet_diagnostic.IDE0054.severity = none # Use compound assignment +dotnet_diagnostic.IDE0056.severity = none # Use index operator +dotnet_diagnostic.IDE0062.severity = none # Make local function static +dotnet_diagnostic.IDE0063.severity = none # Use simple using statement +dotnet_diagnostic.IDE0065.severity = none # Using directive placement +dotnet_diagnostic.IDE0070.severity = none # Use System.HashCode.Combine +dotnet_diagnostic.IDE0071.severity = none # Simplify interpolation +dotnet_diagnostic.IDE0072.severity = none # Add missing cases to switch expression +dotnet_diagnostic.IDE0073.severity = none # Use file header +dotnet_diagnostic.IDE0074.severity = none # Use coalesce compound assignment +dotnet_diagnostic.IDE0076.severity = none # Remove invalid global SuppressMessageAttribute +dotnet_diagnostic.IDE0077.severity = none # Avoid legacy format target in global SuppressMessageAttribute +dotnet_diagnostic.IDE0080.severity = none # Remove unnecessary suppression operator +dotnet_diagnostic.IDE0082.severity = none # Convert typeof to nameof +dotnet_diagnostic.IDE0083.severity = none # Use pattern matching (not operator) +dotnet_diagnostic.IDE0090.severity = none # Simplify new expression +dotnet_diagnostic.IDE0100.severity = none # Remove unnecessary equality operator +dotnet_diagnostic.IDE0110.severity = none # Remove unnecessary discard +dotnet_diagnostic.IDE0150.severity = none # Prefer null check over type check +dotnet_diagnostic.IDE0161.severity = none # Use file-scoped namespace +dotnet_diagnostic.IDE0170.severity = none # Simplify property pattern +dotnet_diagnostic.IDE0180.severity = none # Use tuple to swap values +dotnet_diagnostic.IDE0200.severity = none # Remove unnecessary lambda expression +dotnet_diagnostic.IDE0220.severity = none # Add explicit cast in foreach loop +dotnet_diagnostic.IDE0230.severity = none # Use UTF-8 string literal +dotnet_diagnostic.IDE0240.severity = none # Nullable directive is redundant +dotnet_diagnostic.IDE0241.severity = none # Nullable directive is unnecessary +dotnet_diagnostic.IDE0251.severity = none # Member can be made readonly +dotnet_diagnostic.IDE0270.severity = none # Null check can be simplified +dotnet_diagnostic.IDE0280.severity = none # Use nameof +dotnet_diagnostic.IDE0290.severity = none # Use primary constructor +dotnet_diagnostic.IDE0301.severity = none # Use collection expression for empty +dotnet_diagnostic.IDE0302.severity = none # Use collection expression for stackalloc +dotnet_diagnostic.IDE0303.severity = none # Use collection expression for Create() +dotnet_diagnostic.IDE0304.severity = none # Use collection expression for builder +dotnet_diagnostic.IDE0305.severity = none # Use collection expression for fluent +dotnet_diagnostic.IDE0340.severity = none # Use unbound generic type +dotnet_diagnostic.IDE0350.severity = none # Use implicitly typed lambda +dotnet_diagnostic.IDE0380.severity = none # Remove unnecessary unsafe modifier +dotnet_diagnostic.IDE1005.severity = none # Use conditional delegate call + +# Naming and miscellaneous # Naming conventions — SA1300 family already enforces PascalCase / interface # prefix / field casing (with our _underscore convention on SA1306/1309/1311 # deliberately disabled). Leaving IDE1006 off because configuring @@ -846,205 +830,199 @@ dotnet_diagnostic.IDE1006.severity = none # Naming rule violation — SA1300 fam dotnet_diagnostic.IDE3000.severity = none # Disabled per project convention — not enforced ################### -# Roslynator Analyzers (RCS1xxx) - Code Simplification +# Roslynator.CSharp.Analyzers (RCS) ################### -dotnet_diagnostic.RCS1001.severity = error # Add braces (when expression spans over multiple lines) -dotnet_diagnostic.RCS1003.severity = error # Add braces to if-else (when expression spans over multiple lines) +# Code simplification +dotnet_diagnostic.RCS1001.severity = none # Add braces (when expression spans over multiple lines) — covered by SST1519 +dotnet_diagnostic.RCS1003.severity = none # Add braces to if-else (when expression spans over multiple lines) — covered by SST1519 dotnet_diagnostic.RCS1005.severity = error # Simplify nested using statement -dotnet_diagnostic.RCS1006.severity = error # Merge 'else' with nested 'if' +dotnet_diagnostic.RCS1006.severity = none # Merge 'else' with nested 'if' — covered by SST1465 dotnet_diagnostic.RCS1007.severity = error # Add braces dotnet_diagnostic.RCS1031.severity = none # Remove unnecessary braces in switch section -- we don't mind braces in switch statements dotnet_diagnostic.RCS1032.severity = error # Remove redundant parentheses -dotnet_diagnostic.RCS1033.severity = error # Remove redundant boolean literal -dotnet_diagnostic.RCS1039.severity = error # Remove argument list from attribute -dotnet_diagnostic.RCS1042.severity = error # Remove enum default underlying type +dotnet_diagnostic.RCS1033.severity = none # Remove redundant boolean literal — covered by SST1143 +dotnet_diagnostic.RCS1039.severity = none # Remove argument list from attribute — covered by SST1411 +dotnet_diagnostic.RCS1040.severity = none # Remove empty statement — covered by SST1180 +dotnet_diagnostic.RCS1042.severity = none # Remove enum default underlying type — covered by SST1177 dotnet_diagnostic.RCS1043.severity = error # Remove 'partial' modifier from type with a single part -dotnet_diagnostic.RCS1049.severity = error # Simplify boolean comparison -dotnet_diagnostic.RCS1058.severity = error # Use compound assignment -dotnet_diagnostic.RCS1061.severity = error # Merge 'if' with nested 'if' -dotnet_diagnostic.RCS1068.severity = error # Simplify logical negation -dotnet_diagnostic.RCS1069.severity = error # Remove unnecessary case label -dotnet_diagnostic.RCS1070.severity = error # Remove redundant default switch section -dotnet_diagnostic.RCS1071.severity = error # Remove redundant base constructor call -dotnet_diagnostic.RCS1073.severity = error # Convert 'if' to 'return' statement -dotnet_diagnostic.RCS1074.severity = error # Remove redundant constructor -dotnet_diagnostic.RCS1078.severity = error # Use "" or 'string.Empty' -dotnet_diagnostic.RCS1084.severity = error # Use coalesce expression instead of conditional expression -dotnet_diagnostic.RCS1085.severity = error # Use auto-implemented property +dotnet_diagnostic.RCS1049.severity = none # Simplify boolean comparison — covered by SST1143 +dotnet_diagnostic.RCS1058.severity = none # Use compound assignment — covered by SST1185 +dotnet_diagnostic.RCS1061.severity = none # Merge 'if' with nested 'if' — covered by SST2013 +dotnet_diagnostic.RCS1068.severity = none # Simplify logical negation — covered by SST1172/SST2006 +dotnet_diagnostic.RCS1069.severity = none # Remove unnecessary case label — covered by SST1466 +dotnet_diagnostic.RCS1070.severity = none # Remove redundant default switch section — covered by SST1179 +dotnet_diagnostic.RCS1071.severity = none # Remove redundant base constructor call — covered by SST1178 +dotnet_diagnostic.RCS1072.severity = none # Remove empty namespace declaration — covered by SST1435 +dotnet_diagnostic.RCS1073.severity = none # Convert 'if' to 'return' statement — covered by SST1197 +dotnet_diagnostic.RCS1074.severity = none # Remove redundant constructor — covered by SST1433 +dotnet_diagnostic.RCS1078.severity = none # Use "" or 'string.Empty' — conflicts with SST1122, which owns the string.Empty direction +dotnet_diagnostic.RCS1084.severity = none # Use coalesce expression instead of conditional expression — covered by SST1195 +dotnet_diagnostic.RCS1085.severity = none # Use auto-implemented property — covered by SST1420 dotnet_diagnostic.RCS1089.severity = error # Use --/++ operator instead of assignment dotnet_diagnostic.RCS1097.severity = error # Remove redundant 'ToString' call dotnet_diagnostic.RCS1103.severity = error # Convert 'if' to assignment -dotnet_diagnostic.RCS1104.severity = error # Simplify conditional expression +dotnet_diagnostic.RCS1104.severity = none # Simplify conditional expression — covered by SST1182 dotnet_diagnostic.RCS1105.severity = error # Unnecessary interpolation -dotnet_diagnostic.RCS1107.severity = error # Remove redundant 'ToCharArray' call +dotnet_diagnostic.RCS1106.severity = none # Remove empty destructor — covered by PSH1002 +dotnet_diagnostic.RCS1107.severity = none # Remove redundant 'ToCharArray' call — covered by PSH1217 dotnet_diagnostic.RCS1114.severity = error # Remove redundant delegate creation dotnet_diagnostic.RCS1124.severity = error # Inline local variable dotnet_diagnostic.RCS1126.severity = error # Add braces to if-else dotnet_diagnostic.RCS1128.severity = error # Use coalesce expression -dotnet_diagnostic.RCS1129.severity = error # Remove redundant field initialization -dotnet_diagnostic.RCS1132.severity = error # Remove redundant overriding member +dotnet_diagnostic.RCS1129.severity = none # Remove redundant field initialization — covered by SST1176 +dotnet_diagnostic.RCS1132.severity = none # Remove redundant overriding member — covered by SST1181 dotnet_diagnostic.RCS1133.severity = error # Remove redundant Dispose/Close call -dotnet_diagnostic.RCS1134.severity = error # Remove redundant statement +dotnet_diagnostic.RCS1134.severity = none # Remove redundant statement — covered by SST1174 dotnet_diagnostic.RCS1143.severity = error # Simplify coalesce expression dotnet_diagnostic.RCS1145.severity = error # Remove redundant 'as' operator dotnet_diagnostic.RCS1146.severity = error # Use conditional access -dotnet_diagnostic.RCS1151.severity = error # Remove redundant cast +dotnet_diagnostic.RCS1151.severity = none # Remove redundant cast — covered by SST1175 dotnet_diagnostic.RCS1171.severity = error # Simplify lazy initialization dotnet_diagnostic.RCS1173.severity = error # Use coalesce expression instead of 'if' -dotnet_diagnostic.RCS1174.severity = error # Remove redundant async/await +dotnet_diagnostic.RCS1174.severity = none # Remove redundant async/await — covered by PSH1311 dotnet_diagnostic.RCS1179.severity = error # Unnecessary assignment dotnet_diagnostic.RCS1180.severity = error # Inline lazy initialization -dotnet_diagnostic.RCS1188.severity = error # Remove redundant auto-property initialization -dotnet_diagnostic.RCS1192.severity = error # Unnecessary usage of verbatim string literal +dotnet_diagnostic.RCS1188.severity = none # Remove redundant auto-property initialization — covered by SST1176 +dotnet_diagnostic.RCS1192.severity = none # Unnecessary usage of verbatim string literal — covered by SST1184 dotnet_diagnostic.RCS1199.severity = error # Unnecessary null check dotnet_diagnostic.RCS1206.severity = error # Use conditional access instead of conditional expression -dotnet_diagnostic.RCS1207.severity = error # Use anonymous function or method group -dotnet_diagnostic.RCS1211.severity = error # Remove unnecessary 'else' +dotnet_diagnostic.RCS1207.severity = none # Use anonymous function or method group — conflicts with SST2239, which owns the method-group direction +dotnet_diagnostic.RCS1211.severity = none # Remove unnecessary 'else' — covered by SST1464 dotnet_diagnostic.RCS1212.severity = error # Remove redundant assignment -dotnet_diagnostic.RCS1214.severity = error # Unnecessary interpolated string +dotnet_diagnostic.RCS1214.severity = none # Unnecessary interpolated string — covered by SST1183 dotnet_diagnostic.RCS1216.severity = error # Unnecessary unsafe context -dotnet_diagnostic.RCS1217.severity = error # Convert interpolated string to concatenation +dotnet_diagnostic.RCS1217.severity = none # Convert interpolated string to concatenation — reverses SST2249, which owns the concatenation-to-interpolation direction dotnet_diagnostic.RCS1218.severity = error # Simplify code branching -dotnet_diagnostic.RCS1220.severity = error # Use pattern matching instead of combination of 'is' and cast +dotnet_diagnostic.RCS1220.severity = none # Use pattern matching instead of combination of 'is' and cast — covered by SST2007 dotnet_diagnostic.RCS1221.severity = error # Use pattern matching instead of combination of 'as' and null check -dotnet_diagnostic.RCS1238.severity = error # Avoid nested ?: operators -dotnet_diagnostic.RCS1244.severity = error # Simplify 'default' expression +dotnet_diagnostic.RCS1238.severity = none # Avoid nested ?: operators — covered by SST1147 +dotnet_diagnostic.RCS1244.severity = none # Simplify 'default' expression — covered by SST1188 dotnet_diagnostic.RCS1249.severity = none # Unnecessary null-forgiving operator — disabled because multi-TFM nullability annotations can differ per platform, leading to false positives dotnet_diagnostic.RCS1251.severity = error # Remove unnecessary braces from record declaration dotnet_diagnostic.RCS1259.severity = error # Remove empty syntax (replaces RCS1066) dotnet_diagnostic.RCS1262.severity = error # Unnecessary raw string literal -dotnet_diagnostic.RCS1265.severity = error # Remove redundant catch block +dotnet_diagnostic.RCS1265.severity = none # Remove redundant catch block — covered by SST1470 dotnet_diagnostic.RCS1268.severity = error # Simplify numeric comparison -################### -# Roslynator Analyzers (RCS1xxx) - Code Quality -################### -dotnet_diagnostic.RCS1013.severity = error # Use predefined type +# Code quality +dotnet_diagnostic.RCS1013.severity = none # Use predefined type — covered by SST1121 dotnet_diagnostic.RCS1014.severity = error # Use explicitly/implicitly typed array dotnet_diagnostic.RCS1015.severity = error # Use nameof operator -dotnet_diagnostic.RCS1016.severity = error # Use block body or expression body -dotnet_diagnostic.RCS1020.severity = error # Simplify Nullable to T? +dotnet_diagnostic.RCS1016.severity = none # Use block body or expression body — conflicts with SST2219, which owns the expression-bodied accessor direction +dotnet_diagnostic.RCS1020.severity = none # Covered by SST2234 (canonical) dotnet_diagnostic.RCS1021.severity = error # Convert lambda expression body to expression body -dotnet_diagnostic.RCS1044.severity = error # Remove original exception from throw statement -dotnet_diagnostic.RCS1046.severity = none # Asynchronous method name should end with 'Async' — TUnit test method naming convention doesn't follow the Async suffix +dotnet_diagnostic.RCS1044.severity = none # Remove original exception from throw statement — covered by SST1430 +dotnet_diagnostic.RCS1046.severity = none # Asynchronous method name should end with 'Async' — TUnit test method naming convention doesn't follow the Async suffix — covered by SST1317 dotnet_diagnostic.RCS1047.severity = error # Non-asynchronous method name should not end with 'Async' -dotnet_diagnostic.RCS1048.severity = error # Use lambda expression instead of anonymous method +dotnet_diagnostic.RCS1048.severity = none # Use lambda expression instead of anonymous method — covered by SST1130 dotnet_diagnostic.RCS1050.severity = error # Include/omit parentheses when creating new object -dotnet_diagnostic.RCS1051.severity = error # Add/remove parentheses from condition in conditional operator +dotnet_diagnostic.RCS1051.severity = none # Add/remove parentheses from condition in conditional operator — conflicts with SST1459, which owns the non-grouping-parenthesis removal direction dotnet_diagnostic.RCS1056.severity = none # Avoid usage of using alias directive - used to avoid conflicts -dotnet_diagnostic.RCS1059.severity = error # Avoid locking on publicly accessible instance -dotnet_diagnostic.RCS1075.severity = error # Avoid empty catch clause that catches System.Exception +dotnet_diagnostic.RCS1059.severity = none # Avoid locking on publicly accessible instance — covered by SST1901 +dotnet_diagnostic.RCS1075.severity = none # Avoid empty catch clause that catches System.Exception — covered by SST1429 dotnet_diagnostic.RCS1079.severity = error # Throwing of new NotImplementedException dotnet_diagnostic.RCS1081.severity = error # Split variable declaration dotnet_diagnostic.RCS1093.severity = error # File contains no code -dotnet_diagnostic.RCS1094.severity = error # Declare using directive on top level -dotnet_diagnostic.RCS1096.severity = error # Use 'HasFlag' method or bitwise operator -dotnet_diagnostic.RCS1098.severity = error # Constant values should be placed on right side of comparisons -dotnet_diagnostic.RCS1099.severity = error # Default label should be the last label in a switch section -dotnet_diagnostic.RCS1102.severity = error # Make class static +dotnet_diagnostic.RCS1094.severity = none # Declare using directive on top level — covered by SST1200 +dotnet_diagnostic.RCS1096.severity = none # Use 'HasFlag' method or bitwise operator — covered by PSH1016 +dotnet_diagnostic.RCS1098.severity = none # Constant values should be placed on right side of comparisons — covered by SST1186 +dotnet_diagnostic.RCS1099.severity = none # Default label should be the last label in a switch section — covered by SST1466 +dotnet_diagnostic.RCS1102.severity = none # Make class static — covered by SST1432 dotnet_diagnostic.RCS1108.severity = error # Add 'static' modifier to all partial class declarations dotnet_diagnostic.RCS1111.severity = error # Add braces to switch section with multiple statements dotnet_diagnostic.RCS1113.severity = error # Use 'string.IsNullOrEmpty' method -dotnet_diagnostic.RCS1118.severity = error # Mark local variable as const -dotnet_diagnostic.RCS1123.severity = error # Add parentheses when necessary -dotnet_diagnostic.RCS1130.severity = error # Bitwise operation on enum without Flags attribute +dotnet_diagnostic.RCS1118.severity = none # Mark local variable as const — covered by PSH1402 +dotnet_diagnostic.RCS1123.severity = none # Add parentheses when necessary — covered by SST1407 +dotnet_diagnostic.RCS1130.severity = none # Bitwise operation on enum without Flags attribute — covered by SST2458 dotnet_diagnostic.RCS1135.severity = error # Declare enum member with zero value (when enum has FlagsAttribute) -dotnet_diagnostic.RCS1136.severity = error # Merge switch sections with equivalent content +dotnet_diagnostic.RCS1136.severity = none # Merge switch sections with equivalent content — covered by SST2414 dotnet_diagnostic.RCS1154.severity = error # Sort enum members -dotnet_diagnostic.RCS1155.severity = error # Use StringComparison when comparing strings -dotnet_diagnostic.RCS1156.severity = error # Use string.Length instead of comparison with empty string -dotnet_diagnostic.RCS1157.severity = error # Composite enum value contains undefined flag +dotnet_diagnostic.RCS1155.severity = none # Use StringComparison when comparing strings — covered by PSH1207 +dotnet_diagnostic.RCS1156.severity = none # Use string.Length instead of comparison with empty string — covered by PSH1204 +dotnet_diagnostic.RCS1157.severity = none # Composite enum value contains undefined flag — covered by SST2303 dotnet_diagnostic.RCS1159.severity = error # Use EventHandler -dotnet_diagnostic.RCS1160.severity = error # Abstract type should not have public constructors +dotnet_diagnostic.RCS1160.severity = none # Abstract type should not have public constructors — covered by SST1428 dotnet_diagnostic.RCS1161.severity = none # Enum should declare explicit values - do not need explicit values -dotnet_diagnostic.RCS1162.severity = error # Avoid chain of assignments -dotnet_diagnostic.RCS1166.severity = error # Value type object is never equal to null -dotnet_diagnostic.RCS1168.severity = suggestion # Parameter name differs from base name +dotnet_diagnostic.RCS1162.severity = none # Avoid chain of assignments — covered by SST1187 +dotnet_diagnostic.RCS1166.severity = none # Value type object is never equal to null — covered by SST1469 +dotnet_diagnostic.RCS1168.severity = none # Parameter name differs from base name — covered by SST1318 dotnet_diagnostic.RCS1169.severity = error # Make field read-only dotnet_diagnostic.RCS1170.severity = error # Use read-only auto-implemented property -dotnet_diagnostic.RCS1172.severity = error # Use 'is' operator instead of 'as' operator -dotnet_diagnostic.RCS1187.severity = error # Use constant instead of field +dotnet_diagnostic.RCS1172.severity = none # Use 'is' operator instead of 'as' operator — covered by SST2005 +dotnet_diagnostic.RCS1187.severity = none # Use constant instead of field — covered by PSH1402 dotnet_diagnostic.RCS1191.severity = error # Declare enum value as combination of names -dotnet_diagnostic.RCS1193.severity = error # Overriding member should not change 'params' modifier +dotnet_diagnostic.RCS1193.severity = none # Overriding member should not change 'params' modifier — covered by SST2426 dotnet_diagnostic.RCS1196.severity = error # Call extension method as instance method -dotnet_diagnostic.RCS1200.severity = error # Call 'Enumerable.ThenBy' instead of 'Enumerable.OrderBy' +dotnet_diagnostic.RCS1200.severity = none # Call 'Enumerable.ThenBy' instead of 'Enumerable.OrderBy' — covered by PSH1108 dotnet_diagnostic.RCS1201.severity = error # Use method chaining dotnet_diagnostic.RCS1202.severity = error # Avoid NullReferenceException dotnet_diagnostic.RCS1204.severity = error # Use EventArgs.Empty dotnet_diagnostic.RCS1205.severity = error # Order named arguments according to the order of parameters dotnet_diagnostic.RCS1208.severity = error # Reduce 'if' nesting dotnet_diagnostic.RCS1209.severity = error # Order type parameter constraints -dotnet_diagnostic.RCS1210.severity = error # Return completed task instead of returning null +dotnet_diagnostic.RCS1210.severity = none # Return completed task instead of returning null — covered by PSH1312 dotnet_diagnostic.RCS1215.severity = error # Expression is always equal to true/false dotnet_diagnostic.RCS1222.severity = error # Merge preprocessor directives dotnet_diagnostic.RCS1223.severity = suggestion # Mark publicly visible type with DebuggerDisplay attribute — only data types benefit; the rule is too broad to be an error dotnet_diagnostic.RCS1224.severity = error # Make method an extension method dotnet_diagnostic.RCS1225.severity = error # Make class sealed -dotnet_diagnostic.RCS1227.severity = error # Validate arguments correctly +dotnet_diagnostic.RCS1227.severity = none # Validate arguments correctly — covered by SST2404 dotnet_diagnostic.RCS1229.severity = error # Use async/await when necessary -dotnet_diagnostic.RCS1231.severity = suggestion # Make parameter ref read-only -dotnet_diagnostic.RCS1233.severity = error # Use short-circuiting operator +dotnet_diagnostic.RCS1231.severity = none # Make parameter ref read-only — covered by PSH1007 +dotnet_diagnostic.RCS1233.severity = none # Use short-circuiting operator — covered by SST1468 dotnet_diagnostic.RCS1234.severity = error # Duplicate enum value dotnet_diagnostic.RCS1239.severity = error # Use 'for' statement instead of 'while' statement dotnet_diagnostic.RCS1240.severity = error # Operator is unnecessary -dotnet_diagnostic.RCS1242.severity = error # Do not pass non-read-only struct by read-only reference -dotnet_diagnostic.RCS1243.severity = error # Duplicate word in a comment +dotnet_diagnostic.RCS1242.severity = none # Do not pass non-read-only struct by read-only reference — covered by PSH1003 +dotnet_diagnostic.RCS1243.severity = none # Duplicate word in a comment — covered by SST1658 (documentation comments) dotnet_diagnostic.RCS1247.severity = error # Fix documentation comment tag -dotnet_diagnostic.RCS1248.severity = error # Normalize null check -dotnet_diagnostic.RCS1250.severity = error # Use implicit/explicit object creation +dotnet_diagnostic.RCS1248.severity = none # Normalize null check — conflicts with SST1149, which owns the 'is null' pattern direction +dotnet_diagnostic.RCS1250.severity = none # Use implicit/explicit object creation — conflicts with SST2202, which owns the implicit-target-type direction dotnet_diagnostic.RCS1252.severity = error # Normalize usage of infinite loop dotnet_diagnostic.RCS1254.severity = error # Normalize format of enum flag value dotnet_diagnostic.RCS1255.severity = none # Simplify argument null check — conflicts with our ArgumentExceptionHelper helper pattern dotnet_diagnostic.RCS1257.severity = error # Use enum field explicitly dotnet_diagnostic.RCS1258.severity = error # Unnecessary enum flag -dotnet_diagnostic.RCS1260.severity = error # Add/remove trailing comma -dotnet_diagnostic.RCS1261.severity = error # Resource can be disposed asynchronously +dotnet_diagnostic.RCS1260.severity = none # Add/remove trailing comma — conflicts with SST1413, which owns the trailing-comma direction +dotnet_diagnostic.RCS1261.severity = none # Resource can be disposed asynchronously — covered by PSH1310 dotnet_diagnostic.RCS1264.severity = error # Use 'var' or explicit type (replaces RCS1010, RCS1176, RCS1177) -dotnet_diagnostic.RCS1266.severity = error # Use raw string literal +dotnet_diagnostic.RCS1266.severity = none # Use raw string literal — covered by SST2243 dotnet_diagnostic.RCS1267.severity = error # Use string interpolation instead of 'string.Concat' -################### -# Roslynator Analyzers (RCS1xxx) - Performance -################### -dotnet_diagnostic.RCS1077.severity = error # Optimize LINQ method call -dotnet_diagnostic.RCS1080.severity = error # Use 'Count/Length' property instead of 'Any' method -dotnet_diagnostic.RCS1112.severity = error # Combine 'Enumerable.Where' method chain +# Performance +dotnet_diagnostic.RCS1077.severity = none # Covered by the PSH1101-PSH1111 family (canonical) +dotnet_diagnostic.RCS1080.severity = none # Covered by PSH1106 (canonical) +dotnet_diagnostic.RCS1112.severity = none # Combine 'Enumerable.Where' method chain — covered by PSH1109 dotnet_diagnostic.RCS1186.severity = error # Use Regex instance instead of static method -dotnet_diagnostic.RCS1190.severity = error # Join string expressions +dotnet_diagnostic.RCS1190.severity = none # Join string expressions — conflicts with SST2470, which reports the fused-literal seam this would create dotnet_diagnostic.RCS1195.severity = error # Use ^ operator -dotnet_diagnostic.RCS1197.severity = error # Optimize StringBuilder.Append/AppendLine call +dotnet_diagnostic.RCS1197.severity = none # Optimize StringBuilder.Append/AppendLine call — covered by PSH1203/PSH1214 dotnet_diagnostic.RCS1198.severity = none # Avoid unnecessary boxing of value type — boxing is unavoidable bridging Rx and IEnumerable -dotnet_diagnostic.RCS1230.severity = error # Unnecessary explicit use of enumerator +dotnet_diagnostic.RCS1230.severity = none # Unnecessary explicit use of enumerator — covered by SST1467 dotnet_diagnostic.RCS1235.severity = error # Optimize method call -dotnet_diagnostic.RCS1236.severity = error # Use exception filter -dotnet_diagnostic.RCS1246.severity = error # Use element access +dotnet_diagnostic.RCS1236.severity = none # Use exception filter — covered by SST2009 +dotnet_diagnostic.RCS1246.severity = none # Use element access — covered by PSH1106 -################### -# Roslynator Analyzers (RCS1xxx) - Maintainability -################### -dotnet_diagnostic.RCS1158.severity = none # Static member in generic type should use a type parameter — common factory pattern +# Maintainability +dotnet_diagnostic.RCS1158.severity = none # Static member in generic type should use a type parameter — common factory pattern — covered by SST1431 dotnet_diagnostic.RCS1163.severity = none # Unused parameter — interface implementations and Rx selectors often have unused parameters dotnet_diagnostic.RCS1164.severity = none # Unused type parameter - DUPLICATE IDE0060 (UnusedParameter analyzer 210ms; IDE0060 bundled at lower cost) dotnet_diagnostic.RCS1165.severity = none # Unconstrained type parameter checked for null - we validate all parameters for non-nullable enabled platforms -dotnet_diagnostic.RCS1182.severity = error # Remove redundant base interface +dotnet_diagnostic.RCS1182.severity = none # Remove redundant base interface — covered by SST1177 dotnet_diagnostic.RCS1213.severity = none # Remove unused member declaration - DUPLICATE IDE0051 (slower: 230ms vs 75ms) dotnet_diagnostic.RCS1241.severity = error # Implement non-generic counterpart dotnet_diagnostic.RCS1256.severity = none # Invalid argument null check — conflicts with our ArgumentExceptionHelper helper pattern -################### -# Roslynator Analyzers (RCS1xxx) - Documentation -################### +# Documentation dotnet_diagnostic.RCS1181.severity = error # Convert comment to documentation comment dotnet_diagnostic.RCS1189.severity = error # Add or remove region name dotnet_diagnostic.RCS1226.severity = none # Add paragraph to documentation comment — <para> wrapping is subjective and adds noise dotnet_diagnostic.RCS1228.severity = error # Unused element in a documentation comment dotnet_diagnostic.RCS1232.severity = error # Order elements in documentation comment dotnet_diagnostic.RCS1253.severity = error # Format documentation comment summary -dotnet_diagnostic.RCS1263.severity = error # Invalid reference in a documentation comment +dotnet_diagnostic.RCS1263.severity = none # Invalid reference in a documentation comment -################### -# Roslynator Analyzers (RCS1xxx) - Disabled (covered by CA/SA equivalent) -################### +# Disabled dotnet_diagnostic.RCS1018.severity = none # Add/remove accessibility modifiers — covered by SA1400 dotnet_diagnostic.RCS1019.severity = none # Order modifiers — covered by SA1206 / SA1208 dotnet_diagnostic.RCS1037.severity = none # Remove trailing white-space — covered by SA1028 @@ -1062,9 +1040,7 @@ dotnet_diagnostic.RCS1175.severity = none # Unused 'this' parameter — covered dotnet_diagnostic.RCS1194.severity = none # Implement exception constructors — covered by CA1032 dotnet_diagnostic.RCS1203.severity = none # Use AttributeUsageAttribute — covered by CA1018 -################### -# Roslynator Formatting Analyzers (RCS0xxx) - covered by StyleCop SA equivalents -################### +# Formatting dotnet_diagnostic.RCS0001.severity = none # Add blank line after embedded statement — covered by StyleCop layout rules dotnet_diagnostic.RCS0002.severity = none # Add blank line after #region — covered by StyleCop SA1517 family dotnet_diagnostic.RCS0003.severity = none # Add blank line after using directive list — covered by SA1516 @@ -1109,221 +1085,940 @@ dotnet_diagnostic.RCS0054.severity = none # Fix formatting of a call chain — f dotnet_diagnostic.RCS0055.severity = none # Fix formatting of a binary expression chain — formatting preference dotnet_diagnostic.RCS0056.severity = none # A line is too long — line-length not enforced dotnet_diagnostic.RCS0057.severity = none # Normalize whitespace at the beginning of a file — handled by editorconfig -dotnet_diagnostic.RCS0058.severity = none # Normalize whitespace at the end of a file — covered by SA1518 -dotnet_diagnostic.RCS0059.severity = none # Place new line after/before null-conditional operator — StyleCop wrapping rules cover this +dotnet_diagnostic.RCS0058.severity = none # Normalize whitespace at the end of a file — covered by SST1518 +dotnet_diagnostic.RCS0059.severity = none # Place new line after/before null-conditional operator — StyleSharp wrapping rules cover this dotnet_diagnostic.RCS0060.severity = none # Add/remove line after file scoped namespace declaration — formatting preference dotnet_diagnostic.RCS0061.severity = none # Add/remove blank line between switch sections — formatting preference dotnet_diagnostic.RCS0062.severity = none # Put expression body on its own line — formatting preference -dotnet_diagnostic.RCS0063.severity = none # Remove unnecessary blank line — covered by SA1505 / SA1507 - -################### -# StyleCop Analyzers (SA) - Spacing Rules -################### -dotnet_diagnostic.SA1000.severity = error # Keywords must be spaced correctly -dotnet_diagnostic.SA1001.severity = error # Commas must be spaced correctly -dotnet_diagnostic.SA1002.severity = error # Semicolons must be spaced correctly -dotnet_diagnostic.SA1003.severity = error # Symbols must be spaced correctly -dotnet_diagnostic.SA1004.severity = error # Documentation lines must begin with single space -dotnet_diagnostic.SA1005.severity = error # Single line comments must begin with single space -dotnet_diagnostic.SA1006.severity = error # Preprocessor keywords must not be preceded by space -dotnet_diagnostic.SA1007.severity = error # Operator keyword must be followed by space -dotnet_diagnostic.SA1008.severity = error # Opening parenthesis must be spaced correctly -dotnet_diagnostic.SA1009.severity = error # Closing parenthesis must be spaced correctly -dotnet_diagnostic.SA1010.severity = none # Opening square brackets must be spaced correctly — conflicts with C# 12 collection expressions -dotnet_diagnostic.SA1011.severity = error # Closing square brackets must be spaced correctly -dotnet_diagnostic.SA1012.severity = error # Opening braces must be spaced correctly -dotnet_diagnostic.SA1013.severity = error # Closing braces must be spaced correctly -dotnet_diagnostic.SA1014.severity = error # Opening generic brackets must be spaced correctly -dotnet_diagnostic.SA1015.severity = error # Closing generic brackets must be spaced correctly -dotnet_diagnostic.SA1016.severity = error # Opening attribute brackets must be spaced correctly -dotnet_diagnostic.SA1017.severity = error # Closing attribute brackets must be spaced correctly -dotnet_diagnostic.SA1018.severity = error # Nullable type symbols must not be preceded by space -dotnet_diagnostic.SA1019.severity = error # Member access symbols must be spaced correctly -dotnet_diagnostic.SA1020.severity = error # Increment decrement symbols must be spaced correctly -dotnet_diagnostic.SA1021.severity = error # Negative signs must be spaced correctly -dotnet_diagnostic.SA1022.severity = error # Positive signs must be spaced correctly -dotnet_diagnostic.SA1023.severity = error # Dereference and access of symbols must be spaced correctly -dotnet_diagnostic.SA1024.severity = error # Colons must be spaced correctly -dotnet_diagnostic.SA1025.severity = error # Code must not contain multiple whitespace in a row -dotnet_diagnostic.SA1026.severity = error # Code must not contain space after new keyword in implicitly typed array allocation -dotnet_diagnostic.SA1027.severity = error # Use tabs correctly -dotnet_diagnostic.SA1028.severity = error # Code must not contain trailing whitespace - -################### -# StyleCop Analyzers (SA) - Readability Rules -################### -dotnet_diagnostic.SA1100.severity = error # Do not prefix calls with base unless local implementation exists -dotnet_diagnostic.SA1101.severity = none # Prefix local calls with this — we don't follow the this. prefix style -dotnet_diagnostic.SA1102.severity = error # Query clause must follow previous clause -dotnet_diagnostic.SA1103.severity = error # Query clauses must be on same line or separate lines -dotnet_diagnostic.SA1104.severity = error # Query clause must begin on new line when previous clause spans multiple lines -dotnet_diagnostic.SA1105.severity = error # Query clauses spanning multiple lines must begin on own line -dotnet_diagnostic.SA1106.severity = error # Code must not contain empty statements -dotnet_diagnostic.SA1107.severity = error # Code must not contain multiple statements on one line -dotnet_diagnostic.SA1108.severity = error # Block statements must not contain embedded comments -dotnet_diagnostic.SA1110.severity = error # Opening parenthesis or bracket must be on declaration line -dotnet_diagnostic.SA1111.severity = error # Closing parenthesis must be on line of last parameter -dotnet_diagnostic.SA1112.severity = error # Closing parenthesis must be on line of opening parenthesis -dotnet_diagnostic.SA1113.severity = error # Comma must be on same line as previous parameter -dotnet_diagnostic.SA1114.severity = error # Parameter list must follow declaration -dotnet_diagnostic.SA1115.severity = error # Parameter must follow comma -dotnet_diagnostic.SA1116.severity = error # Split parameters must start on line after declaration -dotnet_diagnostic.SA1117.severity = error # Parameters must be on same line or separate lines -dotnet_diagnostic.SA1118.severity = error # Parameter must not span multiple lines -dotnet_diagnostic.SA1120.severity = error # Comments must contain text -dotnet_diagnostic.SA1121.severity = none # Use built-in type alias - DUPLICATE RCS1013 (slower: 330ms vs 19ms) -dotnet_diagnostic.SA1122.severity = error # Use string.Empty for empty strings -dotnet_diagnostic.SA1123.severity = error # Do not place regions within elements -dotnet_diagnostic.SA1124.severity = error # Do not use regions -dotnet_diagnostic.SA1125.severity = error # Use shorthand for nullable types -dotnet_diagnostic.SA1127.severity = error # Generic type constraints must be on own line -dotnet_diagnostic.SA1128.severity = error # Constructor initializer must be on own line -dotnet_diagnostic.SA1129.severity = error # Do not use default value type constructor -dotnet_diagnostic.SA1130.severity = error # Use lambda syntax -dotnet_diagnostic.SA1131.severity = error # Use readable conditions -dotnet_diagnostic.SA1132.severity = error # Do not combine fields -dotnet_diagnostic.SA1133.severity = error # Do not combine attributes -dotnet_diagnostic.SA1134.severity = error # Attributes must not share line -dotnet_diagnostic.SA1135.severity = error # Using directives must be qualified -dotnet_diagnostic.SA1136.severity = error # Enum values should be on separate lines -dotnet_diagnostic.SA1137.severity = error # Elements should have the same indentation -dotnet_diagnostic.SA1139.severity = error # Use literal suffix notation instead of casting - -################### -# StyleCop Analyzers (SA) - Ordering Rules -################### -dotnet_diagnostic.SA1200.severity = none # Using directives must be placed correctly — usings live outside file-scoped namespaces -dotnet_diagnostic.SA1201.severity = error # Elements must appear in the correct order -dotnet_diagnostic.SA1202.severity = error # Elements must be ordered by access -dotnet_diagnostic.SA1203.severity = error # Constants must appear before fields -dotnet_diagnostic.SA1204.severity = error # Static elements must appear before instance elements -dotnet_diagnostic.SA1205.severity = error # Partial elements must declare access -dotnet_diagnostic.SA1206.severity = error # Declaration keywords must follow order -dotnet_diagnostic.SA1207.severity = error # Protected must come before internal -dotnet_diagnostic.SA1208.severity = error # System using directives must be placed before other using directives -dotnet_diagnostic.SA1209.severity = error # Using alias directives must be placed after other using directives -dotnet_diagnostic.SA1210.severity = error # Using directives must be ordered alphabetically by namespace -dotnet_diagnostic.SA1211.severity = error # Using alias directives must be ordered alphabetically by alias name -dotnet_diagnostic.SA1212.severity = error # Property accessors must follow order -dotnet_diagnostic.SA1213.severity = error # Event accessors must follow order -dotnet_diagnostic.SA1214.severity = error # Readonly elements must appear before non-readonly elements -dotnet_diagnostic.SA1216.severity = error # Using static directives must be placed at the correct location -dotnet_diagnostic.SA1217.severity = error # Using static directives must be ordered alphabetically - -################### -# StyleCop Analyzers (SA) - Naming Rules -################### -dotnet_diagnostic.SA1300.severity = none # Element must begin with upper-case letter - DUPLICATE S100/S101 (slower: 101ms vs 47ms) -dotnet_diagnostic.SA1302.severity = error # Interface names must begin with I -dotnet_diagnostic.SA1303.severity = error # Const field names must begin with upper-case letter -dotnet_diagnostic.SA1304.severity = error # Non-private readonly fields must begin with upper-case letter -dotnet_diagnostic.SA1306.severity = none # Field names must begin with lower-case letter — we use the _underscore prefix for private fields -dotnet_diagnostic.SA1307.severity = error # Accessible fields must begin with upper-case letter -dotnet_diagnostic.SA1308.severity = error # Variable names must not be prefixed -dotnet_diagnostic.SA1309.severity = none # Field names must not begin with underscore — we use the _underscore prefix for private fields -dotnet_diagnostic.SA1310.severity = error # Field names must not contain underscore -dotnet_diagnostic.SA1311.severity = none # Static readonly fields must begin with upper-case letter — we use the _underscore convention for private static readonly fields too -dotnet_diagnostic.SA1312.severity = error # Variable names must begin with lower-case letter -dotnet_diagnostic.SA1313.severity = error # Parameter names must begin with lower-case letter -dotnet_diagnostic.SA1314.severity = error # Type parameter names must begin with T -dotnet_diagnostic.SA1316.severity = none # Tuple element names should use correct casing — we don't enforce a tuple element naming convention - -################### -# StyleCop Analyzers (SA) - Maintainability Rules -################### -dotnet_diagnostic.SA1119.severity = error # Statement must not use unnecessary parenthesis -dotnet_diagnostic.SA1400.severity = error # Access modifier must be declared -dotnet_diagnostic.SA1401.severity = error # Fields must be private -dotnet_diagnostic.SA1402.severity = error # File may only contain a single type -dotnet_diagnostic.SA1403.severity = error # File may only contain a single namespace -dotnet_diagnostic.SA1404.severity = error # Code analysis suppression must have justification -dotnet_diagnostic.SA1405.severity = error # Debug.Assert must provide message text -dotnet_diagnostic.SA1406.severity = error # Debug.Fail must provide message text -dotnet_diagnostic.SA1407.severity = error # Arithmetic expressions must declare precedence -dotnet_diagnostic.SA1408.severity = error # Conditional expressions must declare precedence -dotnet_diagnostic.SA1410.severity = error # Remove delegate parenthesis when possible -dotnet_diagnostic.SA1411.severity = error # Attribute constructor must not use unnecessary parenthesis -dotnet_diagnostic.SA1413.severity = none # Use trailing commas in multi-line initializers — trailing commas not required - -################### -# StyleCop Analyzers (SA) - Layout Rules -################### -dotnet_diagnostic.SA1500.severity = error # Braces for multi-line statements must not share line -dotnet_diagnostic.SA1501.severity = error # Statement must not be on single line -dotnet_diagnostic.SA1502.severity = error # Element must not be on single line -dotnet_diagnostic.SA1503.severity = none # Braces must not be omitted - DUPLICATE S121 (slower: 50ms vs 20ms) -dotnet_diagnostic.SA1504.severity = error # All accessors must be single-line or multi-line -dotnet_diagnostic.SA1505.severity = error # Opening braces must not be followed by blank line -dotnet_diagnostic.SA1506.severity = error # Element documentation headers must not be followed by blank line -dotnet_diagnostic.SA1507.severity = error # Code must not contain multiple blank lines in a row -dotnet_diagnostic.SA1508.severity = error # Closing braces must not be preceded by blank line -dotnet_diagnostic.SA1509.severity = error # Opening braces must not be preceded by blank line -dotnet_diagnostic.SA1510.severity = error # Chained statement blocks must not be preceded by blank line -dotnet_diagnostic.SA1511.severity = error # While-do footer must not be preceded by blank line -dotnet_diagnostic.SA1512.severity = error # Single-line comments must not be followed by blank line -dotnet_diagnostic.SA1513.severity = error # Closing brace must be followed by blank line -dotnet_diagnostic.SA1514.severity = error # Element documentation header must be preceded by blank line -dotnet_diagnostic.SA1515.severity = error # Single-line comment must be preceded by blank line -dotnet_diagnostic.SA1516.severity = error # Elements must be separated by blank line -dotnet_diagnostic.SA1517.severity = error # Code must not contain blank lines at start of file -dotnet_diagnostic.SA1518.severity = error # Use line endings correctly at end of file -dotnet_diagnostic.SA1519.severity = error # Braces must not be omitted from multi-line child statement -dotnet_diagnostic.SA1520.severity = error # Use braces consistently - -################### -# StyleCop Analyzers (SA) - Documentation Rules -################### -dotnet_diagnostic.SA1600.severity = error # Elements must be documented -dotnet_diagnostic.SA1601.severity = error # Partial elements must be documented -dotnet_diagnostic.SA1602.severity = error # Enumeration items must be documented -dotnet_diagnostic.SA1604.severity = error # Element documentation must have summary -dotnet_diagnostic.SA1605.severity = error # Partial element documentation must have summary -dotnet_diagnostic.SA1606.severity = error # Element documentation must have summary text -dotnet_diagnostic.SA1607.severity = error # Partial element documentation must have summary text -dotnet_diagnostic.SA1608.severity = error # Element documentation must not have default summary -dotnet_diagnostic.SA1610.severity = error # Property documentation must have value text -dotnet_diagnostic.SA1611.severity = error # Element parameters must be documented -dotnet_diagnostic.SA1612.severity = error # Element parameter documentation must match element parameters -dotnet_diagnostic.SA1613.severity = error # Element parameter documentation must declare parameter name -dotnet_diagnostic.SA1614.severity = error # Element parameter documentation must have text -dotnet_diagnostic.SA1615.severity = error # Element return value must be documented -dotnet_diagnostic.SA1616.severity = error # Element return value documentation must have text -dotnet_diagnostic.SA1617.severity = error # Void return value must not be documented -dotnet_diagnostic.SA1618.severity = error # Generic type parameters must be documented -dotnet_diagnostic.SA1619.severity = error # Generic type parameters must be documented partial class -dotnet_diagnostic.SA1620.severity = error # Generic type parameter documentation must match type parameters -dotnet_diagnostic.SA1621.severity = error # Generic type parameter documentation must declare parameter name -dotnet_diagnostic.SA1622.severity = error # Generic type parameter documentation must have text -dotnet_diagnostic.SA1623.severity = error # Property summary documentation must match accessors -dotnet_diagnostic.SA1624.severity = error # Property summary documentation must omit set accessor with restricted access -dotnet_diagnostic.SA1625.severity = error # Element documentation must not be copied and pasted -dotnet_diagnostic.SA1626.severity = error # Single-line comments must not use documentation style slashes -dotnet_diagnostic.SA1627.severity = error # Documentation text must not be empty -dotnet_diagnostic.SA1629.severity = error # Documentation text must end with a period -dotnet_diagnostic.SA1633.severity = error # File must have header -dotnet_diagnostic.SA1634.severity = error # File header must show copyright -dotnet_diagnostic.SA1635.severity = error # File header must have copyright text -dotnet_diagnostic.SA1636.severity = error # File header copyright text must match -dotnet_diagnostic.SA1637.severity = none # File header must contain file name — our headers don't include the filename -dotnet_diagnostic.SA1638.severity = none # File header file name documentation must match file name — our headers don't include the filename -dotnet_diagnostic.SA1640.severity = error # File header must have valid company text -dotnet_diagnostic.SA1641.severity = error # File header company name text must match -dotnet_diagnostic.SA1642.severity = error # Constructor summary documentation must begin with standard text -dotnet_diagnostic.SA1643.severity = error # Destructor summary documentation must begin with standard text -dotnet_diagnostic.SA1649.severity = error # File name must match type name -dotnet_diagnostic.SA1651.severity = error # Do not use placeholder elements - -################### -# StyleCop Alternative Analyzers (SX) - Alternative Rules -################### -dotnet_diagnostic.SX1101.severity = error # Do not prefix local members with this -dotnet_diagnostic.SX1309.severity = error # Field names must begin with underscore -dotnet_diagnostic.SX1623.severity = none # Property summary documentation must match accessors (alternative) — alternative SX rule, replaced by standard SA1623 - -################### -# Trimming Analyzer Warnings (IL2001 - IL2123) +dotnet_diagnostic.RCS0063.severity = none # Remove unnecessary blank line — covered by SST1505 / SST1507 + +################### +# StyleSharp Analyzers (SST) +################### +file_header_template = Copyright (c) 2019-2026 ReactiveUI Association Incorporated. All rights reserved.\nReactiveUI Association Incorporated licenses this file to you under the MIT license.\nSee the LICENSE file in the project root for full license information. +stylesharp.summary_single_line_max_length = 120 + +# SonarAnalyzer's S4022 only ever flagged storage narrower than int; uint, long and ulong +# passed silently. Match that, so retiring S4022 for SST2313 does not fail a build on an +# enum that was deliberately widened. +stylesharp.SST2313.allowed_enum_storage = int, uint, long, ulong + +# Documentation coverage scope (SST1600/SST1601/SST1602/SST1654). +# Require documentation on every element, including private members. +stylesharp.document_exposed_elements = true +stylesharp.document_internal_elements = true +stylesharp.document_private_elements = true +stylesharp.document_private_fields = true +stylesharp.document_interfaces = all +stylesharp.SST1305.allowed_hungarian_prefixes = rx +stylesharp.instance_member_qualification = omit_this +stylesharp.max_cyclomatic_complexity = 10 +stylesharp.max_cognitive_complexity = 15 +stylesharp.max_property_cognitive_complexity = 3 +# SST1484 also reports a field that shadows one inherited from a base type. +stylesharp.SST1484.check_base_types = true +stylesharp.max_line_length = 200 # SST1521 (characters; keeps the limit this repo has always enforced) +stylesharp.max_file_lines = 1000 # SST1522 (code lines; blank lines and comments do not count) +# stylesharp.max_member_lines = 60 # SST1523 (code lines) +# stylesharp.max_switch_section_lines = 20 # SST1524 (code lines) +# stylesharp.include_internal = true # SST1499 (set false to report only fields visible outside the assembly) +# stylesharp.require_parameterless = true # SST1488 (set false where every exception must carry a message) +# stylesharp.include_non_public_types = true # SST1488 (set false to check only externally visible exceptions) +# Spacing +dotnet_diagnostic.SST1000.severity = error # A control-flow keyword is not followed by a space +dotnet_diagnostic.SST1001.severity = error # A comma is spaced incorrectly +dotnet_diagnostic.SST1002.severity = error # A semicolon is spaced incorrectly +dotnet_diagnostic.SST1003.severity = error # A binary operator is not surrounded by spaces +dotnet_diagnostic.SST1004.severity = error # A documentation comment line does not begin with a single space after the '///' +dotnet_diagnostic.SST1005.severity = error # A single-line comment does not begin with a single space +dotnet_diagnostic.SST1006.severity = error # A preprocessor keyword is preceded by a space after the '#' +dotnet_diagnostic.SST1007.severity = error # An operator keyword is not followed by a space +dotnet_diagnostic.SST1008.severity = error # An opening parenthesis is followed by a space +dotnet_diagnostic.SST1009.severity = error # A closing parenthesis is preceded by a space +dotnet_diagnostic.SST1010.severity = none # An opening square bracket has adjacent whitespace — conflicts with modern collection expressions +dotnet_diagnostic.SST1011.severity = error # A closing square bracket is preceded by a space +dotnet_diagnostic.SST1012.severity = error # An opening brace is not followed by a space on a single line +dotnet_diagnostic.SST1013.severity = error # A closing brace is not preceded by a space on a single line +dotnet_diagnostic.SST1014.severity = error # An opening generic bracket is preceded or followed by a space +dotnet_diagnostic.SST1015.severity = error # A closing generic bracket is preceded by a space +dotnet_diagnostic.SST1016.severity = error # An opening attribute bracket is followed by a space +dotnet_diagnostic.SST1017.severity = error # A closing attribute bracket is preceded by a space +dotnet_diagnostic.SST1018.severity = error # A nullable type symbol is preceded by a space +dotnet_diagnostic.SST1019.severity = error # A member access symbol is surrounded by spaces +dotnet_diagnostic.SST1020.severity = error # An increment or decrement symbol is separated from its operand by a space +dotnet_diagnostic.SST1021.severity = error # A unary negative sign is followed by a space +dotnet_diagnostic.SST1022.severity = error # A unary positive sign is followed by a space +dotnet_diagnostic.SST1023.severity = error # A dereference or address-of symbol is followed by a space +dotnet_diagnostic.SST1024.severity = error # A colon is spaced incorrectly for its context +dotnet_diagnostic.SST1025.severity = error # Two or more whitespace characters appear in a row within a line +dotnet_diagnostic.SST1026.severity = error # A space follows 'new' or 'stackalloc' in an implicit array creation +dotnet_diagnostic.SST1027.severity = error # A tab character is used where the project standardises on spaces +dotnet_diagnostic.SST1028.severity = error # A line ends with trailing whitespace + +# Readability and maintainability +dotnet_diagnostic.SST1100.severity = error # A base. prefix is used where the type does not override the member +dotnet_diagnostic.SST1101.severity = none # see docs/rules/SST1101.md +dotnet_diagnostic.SST1102.severity = error # A query clause is separated from the previous clause by a blank line +dotnet_diagnostic.SST1103.severity = error # Query clauses mix single-line and multi-line layout +dotnet_diagnostic.SST1104.severity = error # A query clause shares the last line of a multi-line previous clause +dotnet_diagnostic.SST1105.severity = error # A multi-line query clause does not begin on its own line +dotnet_diagnostic.SST1106.severity = error # A statement is empty (a stray semicolon) +dotnet_diagnostic.SST1107.severity = error # More than one statement shares a line +dotnet_diagnostic.SST1110.severity = error # An opening parenthesis or bracket does not sit on the line of the preceding code +dotnet_diagnostic.SST1111.severity = error # A closing parenthesis or bracket does not sit on the last parameter's line +dotnet_diagnostic.SST1112.severity = error # An empty parameter list's closing parenthesis is on a different line +dotnet_diagnostic.SST1113.severity = error # A comma does not sit on the previous parameter's line +dotnet_diagnostic.SST1114.severity = error # A blank line separates the declaration from its parameter list +dotnet_diagnostic.SST1115.severity = error # A blank line separates a parameter from the preceding comma +dotnet_diagnostic.SST1116.severity = error # A qualified name can be shortened without changing the symbol it binds to +dotnet_diagnostic.SST1117.severity = error # Instance member access follows the configured this. qualification style +dotnet_diagnostic.SST1118.severity = none # A parameter should not span multiple lines +dotnet_diagnostic.SST1119.severity = error # A numeric literal groups its digit separators irregularly +dotnet_diagnostic.SST1120.severity = error # A comment contains no text +dotnet_diagnostic.SST1121.severity = error # A framework type name is used instead of its built-in alias (opt-in rule, enabled here) +dotnet_diagnostic.SST1122.severity = error # An empty string literal is used instead of string.Empty +dotnet_diagnostic.SST1123.severity = error # A #region is placed inside a code element body +dotnet_diagnostic.SST1124.severity = error # A #region directive is used +dotnet_diagnostic.SST1125.severity = error # A Nullable type is written in long form instead of the T? shorthand +dotnet_diagnostic.SST1127.severity = error # A generic type constraint shares a line with the declaration or another constraint +dotnet_diagnostic.SST1128.severity = error # A constructor initializer shares a line with the constructor signature +dotnet_diagnostic.SST1129.severity = error # A value type is created with a parameterless constructor call instead of default +dotnet_diagnostic.SST1130.severity = error # An anonymous delegate is used where a lambda expression is clearer +dotnet_diagnostic.SST1131.severity = error # A comparison places the constant on the left ("yoda" condition) +dotnet_diagnostic.SST1132.severity = error # Several fields are declared in a single statement +dotnet_diagnostic.SST1133.severity = error # Several attributes share one bracket list +dotnet_diagnostic.SST1134.severity = error # An attribute shares a line with another attribute or the element +dotnet_diagnostic.SST1135.severity = error # A using directive names a namespace or type that is not fully qualified +dotnet_diagnostic.SST1136.severity = error # Several enum members share a line +dotnet_diagnostic.SST1137.severity = error # Sibling elements are indented differently from one another +dotnet_diagnostic.SST1138.severity = error # A free-standing block declares nothing +dotnet_diagnostic.SST1139.severity = error # A numeric literal is cast where a literal suffix would express the type +dotnet_diagnostic.SST1140.severity = error # Wrapped conditional operators should start indented continuation lines +dotnet_diagnostic.SST1141.severity = error # An explicit ValueTuple<...> is used where tuple syntax would do +dotnet_diagnostic.SST1142.severity = error # A tuple element is accessed by ItemN where it has a name +dotnet_diagnostic.SST1143.severity = error # A boolean expression is compared to a true/false literal +dotnet_diagnostic.SST1144.severity = error # Combine case labels with an or-pattern +dotnet_diagnostic.SST1145.severity = error # A wrapped conditional expression places ?/: inconsistently +dotnet_diagnostic.SST1146.severity = error # An if statement follows a closing brace on the same line +dotnet_diagnostic.SST1147.severity = error # Do not nest conditional operators +dotnet_diagnostic.SST1148.severity = error # Commented-out code should be removed +dotnet_diagnostic.SST1149.severity = error # Prefer the 'is null' pattern for null checks +dotnet_diagnostic.SST1150.severity = error # Require each constructor parameter on a unique line +dotnet_diagnostic.SST1151.severity = error # Require each method parameter on a unique line +dotnet_diagnostic.SST1152.severity = error # Require each delegate parameter on a unique line +dotnet_diagnostic.SST1153.severity = error # Require each indexer parameter on a unique line +dotnet_diagnostic.SST1154.severity = error # Require each invocation argument on a unique line +dotnet_diagnostic.SST1155.severity = error # Require each object creation argument on a unique line +dotnet_diagnostic.SST1156.severity = error # Require each element access argument on a unique line +dotnet_diagnostic.SST1157.severity = error # Require each attribute argument on a unique line +dotnet_diagnostic.SST1158.severity = error # Require each anonymous method parameter on a unique line +dotnet_diagnostic.SST1159.severity = error # Require each parenthesized lambda parameter on a unique line +dotnet_diagnostic.SST1160.severity = error # Require each record primary-constructor parameter on a unique line +dotnet_diagnostic.SST1161.severity = error # Require each class primary-constructor parameter on a unique line +dotnet_diagnostic.SST1162.severity = error # Require each struct primary-constructor parameter on a unique line +dotnet_diagnostic.SST1163.severity = error # Require each target-typed object creation argument on a unique line +dotnet_diagnostic.SST1164.severity = error # Require each constructor initializer argument on a unique line +dotnet_diagnostic.SST1165.severity = error # Require each primary-constructor base argument on a unique line +dotnet_diagnostic.SST1166.severity = error # Require each local-function parameter on a unique line +dotnet_diagnostic.SST1167.severity = error # Require each operator parameter on a unique line +dotnet_diagnostic.SST1168.severity = error # Require each conversion-operator parameter on a unique line +dotnet_diagnostic.SST1169.severity = error # Require each type parameter on a unique line +dotnet_diagnostic.SST1170.severity = error # Require each type argument on a unique line +dotnet_diagnostic.SST1171.severity = error # Require each function-pointer parameter on a unique line +dotnet_diagnostic.SST1172.severity = error # Negated comparisons should use the opposite operator +dotnet_diagnostic.SST1173.severity = error # Redundant anonymous-type member names should be omitted +dotnet_diagnostic.SST1174.severity = error # Redundant jump statements should be removed +dotnet_diagnostic.SST1175.severity = error # Unnecessary casts should be removed +dotnet_diagnostic.SST1176.severity = error # Members should not be initialized to their default value +dotnet_diagnostic.SST1177.severity = error # Redundant base types should be removed +dotnet_diagnostic.SST1178.severity = error # Redundant base constructor calls should be removed +dotnet_diagnostic.SST1179.severity = error # Redundant default switch sections should be removed +dotnet_diagnostic.SST1180.severity = error # Empty else clauses should be removed +dotnet_diagnostic.SST1181.severity = error # Redundant overriding members should be removed +dotnet_diagnostic.SST1182.severity = error # Conditional expressions should not just return boolean literals +dotnet_diagnostic.SST1183.severity = error # Interpolated strings without interpolations should be plain strings +dotnet_diagnostic.SST1184.severity = error # Verbatim string literals without escapes should be regular strings +dotnet_diagnostic.SST1185.severity = error # Use a compound assignment operator +dotnet_diagnostic.SST1186.severity = error # A literal should be on the right side of a comparison +dotnet_diagnostic.SST1187.severity = error # Assignments should not be chained +dotnet_diagnostic.SST1188.severity = error # Use the 'default' literal instead of 'default(T)' +dotnet_diagnostic.SST1189.severity = error # Variables should not be self-assigned +dotnet_diagnostic.SST1190.severity = error # Doubled negation operators should be removed +dotnet_diagnostic.SST1191.severity = error # Long numeric literals should use digit separators +dotnet_diagnostic.SST1192.severity = none # Control characters in string literals should be escaped +dotnet_diagnostic.SST1193.severity = error # Keep initial member values with construction +dotnet_diagnostic.SST1194.severity = error # Keep initial collection values with construction +dotnet_diagnostic.SST1195.severity = error # Write null fallback with ?? +dotnet_diagnostic.SST1196.severity = error # Write null-guarded access with ?. +dotnet_diagnostic.SST1197.severity = error # Collapse return-only branches into one return +dotnet_diagnostic.SST1198.severity = error # Collapse assignment-only branches into one assignment +dotnet_diagnostic.SST1199.severity = error # Prefer compile-time type names + +# Ordering +dotnet_diagnostic.SST1200.severity = error # Using directives should be placed outside the namespace +dotnet_diagnostic.SST1201.severity = error # Members should be ordered by kind +dotnet_diagnostic.SST1202.severity = error # Members should be ordered by accessibility +dotnet_diagnostic.SST1203.severity = error # Constants should appear before fields +dotnet_diagnostic.SST1204.severity = error # Static members should appear before instance members +dotnet_diagnostic.SST1205.severity = error # Partial elements should declare an access modifier +dotnet_diagnostic.SST1206.severity = error # Declaration keywords should follow the standard order +dotnet_diagnostic.SST1207.severity = error # Place protected before internal +dotnet_diagnostic.SST1208.severity = error # System using directives should appear before other usings +dotnet_diagnostic.SST1209.severity = error # Using alias directives should appear after other usings +dotnet_diagnostic.SST1210.severity = error # Regular using directives should be ordered alphabetically +dotnet_diagnostic.SST1211.severity = error # Using alias directives should be ordered alphabetically by alias +dotnet_diagnostic.SST1212.severity = error # Property accessors should be ordered with get first +dotnet_diagnostic.SST1213.severity = error # Event accessors should be ordered with add first +dotnet_diagnostic.SST1214.severity = error # Static readonly fields should appear before static non-readonly fields +dotnet_diagnostic.SST1215.severity = error # Instance readonly fields should appear before instance non-readonly fields +dotnet_diagnostic.SST1216.severity = error # Using static directives should be placed after regular usings and before aliases +dotnet_diagnostic.SST1217.severity = error # Using static directives should be ordered alphabetically +dotnet_diagnostic.SST1218.severity = error # Other members separate a method's overloads +dotnet_diagnostic.SST1219.severity = error # A switch default clause is not placed last +dotnet_diagnostic.SST1220.severity = error # An all-named argument list is in a different order than the parameters. Code fix reorders it to declaration order. Info. +dotnet_diagnostic.SST1221.severity = error # `where` constraint clauses are not ordered to match the type-parameter list. Code fix reorders them. Info. + +# Naming +dotnet_diagnostic.SST1300.severity = none # Types and members should be PascalCase — naming duplicates existing analyzers +dotnet_diagnostic.SST1302.severity = error # Interface names should begin with I +dotnet_diagnostic.SST1303.severity = error # Const names should be PascalCase +dotnet_diagnostic.SST1304.severity = error # Non-private readonly fields should be PascalCase +dotnet_diagnostic.SST1305.severity = error # Field names should not use Hungarian notation +dotnet_diagnostic.SST1306.severity = none # Field names should begin with a lower-case letter — private fields use _camelCase here +dotnet_diagnostic.SST1307.severity = error # Accessible fields should be PascalCase +dotnet_diagnostic.SST1308.severity = none # Field names should not be prefixed with m_ or s_ — too broad for existing conventions +dotnet_diagnostic.SST1309.severity = error # Private fields should be _camelCase +dotnet_diagnostic.SST1310.severity = none # Field names should not contain underscores — conflicts with _camelCase +dotnet_diagnostic.SST1311.severity = none # Static readonly fields should be PascalCase — we use _camelCase for private static readonly too +dotnet_diagnostic.SST1312.severity = error # Local variables should be camelCase +dotnet_diagnostic.SST1313.severity = error # Parameters should be camelCase +dotnet_diagnostic.SST1314.severity = error # Type parameters should begin with T +dotnet_diagnostic.SST1315.severity = error # Union member names should match the configured casing +dotnet_diagnostic.SST1316.severity = none # Tuple element names should use the configured casing — tuple naming is not enforced here +dotnet_diagnostic.SST1317.severity = none # Asynchronous method names should end with 'Async' — conflicts with this project's Rx-compatibility and naming mechanism +dotnet_diagnostic.SST1318.severity = error # Overriding parameter names should match the base declaration +dotnet_diagnostic.SST1319.severity = error # An enumeration's type name is not PascalCase +dotnet_diagnostic.SST1320.severity = error # A parameter name matches its method's name +dotnet_diagnostic.SST1321.severity = none # Public APIs intentionally use Async to describe asynchronous observable behavior without returning an awaitable. + +# Maintainability +dotnet_diagnostic.SST1400.severity = error # An element does not declare an access modifier +dotnet_diagnostic.SST1401.severity = error # A non-private, non-constant field is exposed +dotnet_diagnostic.SST1402.severity = error # A file declares more than one top-level type +dotnet_diagnostic.SST1403.severity = error # A file declares more than one namespace +dotnet_diagnostic.SST1404.severity = error # A code-analysis suppression has no justification +dotnet_diagnostic.SST1405.severity = error # A Debug.Assert call provides no message +dotnet_diagnostic.SST1406.severity = error # A Debug.Fail call provides no message +dotnet_diagnostic.SST1407.severity = error # Mixed-precedence arithmetic is not parenthesized +dotnet_diagnostic.SST1408.severity = error # Mixed conditional operators are not parenthesized +dotnet_diagnostic.SST1410.severity = error # An anonymous method has an empty parameter list +dotnet_diagnostic.SST1411.severity = error # An attribute uses an empty argument list +dotnet_diagnostic.SST1412.severity = none # Store files as UTF-8 with a byte order mark — conflicts with SST1450 (UTF-8 without BOM) +dotnet_diagnostic.SST1413.severity = none # A multi-line initializer omits the trailing comma — trailing commas are not required here +dotnet_diagnostic.SST1414.severity = error # A tuple type in a member signature has an unnamed element +dotnet_diagnostic.SST1415.severity = error # An argument-exception constructor uses a string literal where nameof would track renames +dotnet_diagnostic.SST1416.severity = none # Do not declare public members in a non-public type +dotnet_diagnostic.SST1417.severity = suggestion # Namespace should match the folder structure +dotnet_diagnostic.SST1418.severity = error # Declare precedence when mixing the null-coalescing operator +dotnet_diagnostic.SST1419.severity = error # Remove redundant modifiers +dotnet_diagnostic.SST1420.severity = error # Trivial properties should be auto-implemented +dotnet_diagnostic.SST1421.severity = error # Write-only properties should not be used +dotnet_diagnostic.SST1422.severity = error # Private fields used only as locals should be local variables +dotnet_diagnostic.SST1423.severity = error # Switch statements should not have too many sections +dotnet_diagnostic.SST1424.severity = error # Fields that are never reassigned should be readonly +dotnet_diagnostic.SST1425.severity = error # Do not reassign captured primary-constructor parameters +dotnet_diagnostic.SST1426.severity = error # Use [SuppressMessage] instead of #pragma warning disable +dotnet_diagnostic.SST1427.severity = error # Protected members of sealed types should not be used +dotnet_diagnostic.SST1428.severity = error # Abstract types should not declare public constructors +dotnet_diagnostic.SST1429.severity = error # Empty catch clauses should not swallow the base exception +dotnet_diagnostic.SST1430.severity = error # Rethrow with 'throw;' to preserve the stack trace +dotnet_diagnostic.SST1431.severity = error # Static members of a generic type should use a type parameter +dotnet_diagnostic.SST1432.severity = error # Classes with only static members should be static +dotnet_diagnostic.SST1433.severity = error # Redundant constructors should be removed +dotnet_diagnostic.SST1434.severity = error # see docs/rules/SST1434.md +dotnet_diagnostic.SST1435.severity = error # Empty namespace declarations should be removed +dotnet_diagnostic.SST1436.severity = error # Empty types should not be declared +dotnet_diagnostic.SST1437.severity = error # Empty interfaces should not be declared +dotnet_diagnostic.SST1438.severity = error # Methods should not be empty +dotnet_diagnostic.SST1439.severity = error # Nested code blocks should not be left empty +dotnet_diagnostic.SST1440.severity = error # Private members with no local use should be removed +dotnet_diagnostic.SST1441.severity = error # Private fields assigned but never read should be removed +dotnet_diagnostic.SST1442.severity = error # A function has too many direct branch points +dotnet_diagnostic.SST1443.severity = error # A function has too much nested control flow +dotnet_diagnostic.SST1444.severity = error # A loop cannot naturally reach a second iteration +dotnet_diagnostic.SST1445.severity = error # A using directive is unnecessary +dotnet_diagnostic.SST1446.severity = error # An inheritance chain is deeper than the configured maximum +dotnet_diagnostic.SST1447.severity = error # An equality override delegates to object reference semantics +dotnet_diagnostic.SST1448.severity = error # An argument is passed explicitly to a caller-info parameter +dotnet_diagnostic.SST1449.severity = error # Code writes directly to the console +dotnet_diagnostic.SST1450.severity = error # Store files as UTF-8 without a byte order mark +dotnet_diagnostic.SST1451.severity = error # A DateTime is created without a DateTimeKind +dotnet_diagnostic.SST1452.severity = error # A generic type parameter is never used +dotnet_diagnostic.SST1453.severity = error # Statements after an unconditional exit should be removed +dotnet_diagnostic.SST1454.severity = error # Composite format placeholders should match the supplied arguments +dotnet_diagnostic.SST1455.severity = error # Unsafe modifiers should be used only when unsafe syntax is present +dotnet_diagnostic.SST1456.severity = error # Readonly fields should not store mutable source-defined structs +dotnet_diagnostic.SST1457.severity = error # Global suppressions should point at real declarations +dotnet_diagnostic.SST1458.severity = error # Global suppression targets should use declaration ids directly +dotnet_diagnostic.SST1459.severity = error # Grouping parentheses should be removed when the parent syntax already isolates the expression +dotnet_diagnostic.SST1460.severity = error # Non-mutating struct members should be readonly +dotnet_diagnostic.SST1461.severity = error # Private parameters that are never read should be removed +dotnet_diagnostic.SST1462.severity = error # Suppressions for diagnostics already disabled by config should be removed +dotnet_diagnostic.SST1463.severity = error # Symbol-name strings should use nameof +dotnet_diagnostic.SST1464.severity = error # An else clause follows a branch that always jumps and can be unwrapped +dotnet_diagnostic.SST1465.severity = error # An else block that only wraps an if can collapse to else-if +dotnet_diagnostic.SST1466.severity = error # A case label sharing a section with default is redundant +dotnet_diagnostic.SST1467.severity = error # A hand-driven enumerator loop can use foreach +dotnet_diagnostic.SST1468.severity = error # Boolean logic should use the short-circuiting && and || operators +dotnet_diagnostic.SST1469.severity = error # A non-nullable value type is compared to null +dotnet_diagnostic.SST1470.severity = error # A trailing catch clause that only rethrows should be removed +dotnet_diagnostic.SST1471.severity = error # Magic numbers should be named constants +dotnet_diagnostic.SST1472.severity = error # Signatures should not declare too many parameters +dotnet_diagnostic.SST1473.severity = error # A floating-point value is compared for exact equality (zero comparison allowed by default) +dotnet_diagnostic.SST1474.severity = error # Both sides of an operator are the same expression +dotnet_diagnostic.SST1475.severity = error # A condition repeats an earlier one in the chain, so its branch cannot run +dotnet_diagnostic.SST1476.severity = error # Every branch of a conditional has the same body +dotnet_diagnostic.SST1477.severity = error # An integer division is widened to floating point after it has already truncated +dotnet_diagnostic.SST1478.severity = error # A shift count is zero, negative, or at least the operand's width +dotnet_diagnostic.SST1479.severity = error # A count or length is compared against a value it can never take +dotnet_diagnostic.SST1480.severity = error # An exception is constructed and then discarded +dotnet_diagnostic.SST1481.severity = error # A bitwise operation has a constant operand that makes it pointless +dotnet_diagnostic.SST1482.severity = error # GetHashCode reads mutable state +dotnet_diagnostic.SST1483.severity = error # A constructor calls an overridable member +dotnet_diagnostic.SST1484.severity = error # A declaration shadows an outer field or property (inherited fields included) +dotnet_diagnostic.SST1485.severity = error # A member that must not throw throws +dotnet_diagnostic.SST1486.severity = error # The same string literal is repeated instead of being named +dotnet_diagnostic.SST1487.severity = error # A collection element is assigned twice with nothing reading it in between +dotnet_diagnostic.SST1488.severity = error # An exception type does not declare the standard constructors (parameterless waivable) +dotnet_diagnostic.SST1489.severity = error # An exception type carries serialization members the target framework has obsoleted +dotnet_diagnostic.SST1490.severity = error # A base list names an interface the rest of the list already implies +dotnet_diagnostic.SST1491.severity = error # A modifier restates the declaration's default +dotnet_diagnostic.SST1492.severity = error # A value is tested against what it is then assigned, so the guard decides nothing +dotnet_diagnostic.SST1493.severity = error # A method's whole body is a constant +dotnet_diagnostic.SST1494.severity = error # A trailing argument repeats the parameter's default +dotnet_diagnostic.SST1495.severity = error # '==' compares references on a type that overrides Equals, so the two disagree +dotnet_diagnostic.SST1496.severity = error # An abstract type declares nothing abstract +dotnet_diagnostic.SST1497.severity = error # A local is declared and never read +dotnet_diagnostic.SST1498.severity = error # Only a nested type uses a private member +dotnet_diagnostic.SST1499.severity = error # A static field visible outside its type can still be changed (internal fields included by default) + +# Layout +dotnet_diagnostic.SST1500.severity = error # A brace in a multi-line construct shares its line with other code +dotnet_diagnostic.SST1501.severity = error # A statement block is collapsed onto a single line +dotnet_diagnostic.SST1502.severity = error # An element body is collapsed onto a single line +dotnet_diagnostic.SST1503.severity = none # A control-flow statement omits the braces around its child statement — duplicate with existing brace preferences +dotnet_diagnostic.SST1504.severity = error # The accessors of a property/event mix single-line and multi-line forms +dotnet_diagnostic.SST1505.severity = error # An opening brace is followed by a blank line +dotnet_diagnostic.SST1506.severity = error # An element documentation header is followed by a blank line +dotnet_diagnostic.SST1507.severity = error # Two or more blank lines appear in a row +dotnet_diagnostic.SST1508.severity = error # A closing brace is preceded by a blank line +dotnet_diagnostic.SST1509.severity = error # An opening brace is preceded by a blank line +dotnet_diagnostic.SST1510.severity = error # A chained block such as else/catch/finally is preceded by a blank line +dotnet_diagnostic.SST1511.severity = error # The while footer of a do/while loop is preceded by a blank line +dotnet_diagnostic.SST1512.severity = error # A single-line comment is followed by a blank line +dotnet_diagnostic.SST1513.severity = error # A closing brace is not followed by a blank line +dotnet_diagnostic.SST1514.severity = error # An element documentation header is not preceded by a blank line +dotnet_diagnostic.SST1515.severity = error # A single-line comment is not preceded by a blank line +dotnet_diagnostic.SST1516.severity = error # Adjacent members or namespace elements are not separated by a blank line +dotnet_diagnostic.SST1517.severity = error # The file begins with one or more blank lines +dotnet_diagnostic.SST1518.severity = error # The file does not end with exactly one newline +dotnet_diagnostic.SST1519.severity = error # A multi-line child statement of a control-flow keyword omits its braces +dotnet_diagnostic.SST1520.severity = error # The clauses of an if/else chain use braces inconsistently +dotnet_diagnostic.SST1521.severity = error # A line is longer than the configured maximum (default 120 characters) +dotnet_diagnostic.SST1522.severity = error # A file has more code lines than the configured maximum (default 500) +dotnet_diagnostic.SST1523.severity = error # A member has more code lines than the configured maximum (default 60) +dotnet_diagnostic.SST1524.severity = error # A switch section has more code lines than the configured maximum (default 20) +dotnet_diagnostic.SST1525.severity = error # A multi-statement `switch` section has no braces; the braces-on policy extends to switch sections. Code fix wraps it. +dotnet_diagnostic.SST1526.severity = error # A wrapped binary expression places the operator inconsistently. Configurable (`before`/`after`, default before). Opt-in. +dotnet_diagnostic.SST1527.severity = error # The `=>` of an expression-bodied member wraps inconsistently. Configurable. Opt-in. +dotnet_diagnostic.SST1528.severity = error # The `=` of a wrapped initializer wraps inconsistently. Configurable. Opt-in. +dotnet_diagnostic.SST1529.severity = error # A wrapped `?.`/`.` call chain places the break inconsistently. Configurable. Opt-in. +dotnet_diagnostic.SST1530.severity = error # A newline sits between a type declaration and its base list. Code fix pulls the base list onto the declaration line. Opt-in. +dotnet_diagnostic.SST1531.severity = error # A short object initializer is split across lines. Code fix collapses it when it fits. Opt-in. +dotnet_diagnostic.SST1532.severity = error # A file mixes line endings. Configurable (`lf`/`crlf`, default lf). Opt-in. +dotnet_diagnostic.SST1533.severity = error # A source file contains no code. Opt-in. + +# Documentation +dotnet_diagnostic.SST1600.severity = error # Externally visible members should be documented +dotnet_diagnostic.SST1601.severity = error # Partial elements should be documented +dotnet_diagnostic.SST1602.severity = error # Enumeration members should be documented +dotnet_diagnostic.SST1604.severity = error # Element documentation should contain a summary +dotnet_diagnostic.SST1605.severity = error # Partial element documentation should have a summary +dotnet_diagnostic.SST1606.severity = error # The summary should have text +dotnet_diagnostic.SST1607.severity = error # Partial element summary should have text +dotnet_diagnostic.SST1608.severity = error # Documentation should not use the default placeholder summary +dotnet_diagnostic.SST1609.severity = none # Property documentation should have a value +dotnet_diagnostic.SST1610.severity = error # Property value documentation should have text +dotnet_diagnostic.SST1611.severity = error # Parameters should be documented +dotnet_diagnostic.SST1612.severity = error # Parameter documentation should match the parameters +dotnet_diagnostic.SST1613.severity = error # Parameter documentation should declare a name +dotnet_diagnostic.SST1614.severity = error # Parameter documentation should have text +dotnet_diagnostic.SST1615.severity = error # The return value should be documented + +dotnet_diagnostic.SST1616.severity = error # Return value documentation should have text +dotnet_diagnostic.SST1617.severity = error # A void return value should not be documented +dotnet_diagnostic.SST1618.severity = error # Generic type parameters should be documented +dotnet_diagnostic.SST1619.severity = error # Partial generic type parameters should be documented +dotnet_diagnostic.SST1620.severity = error # Type parameter documentation should match the type parameters +dotnet_diagnostic.SST1621.severity = error # Type parameter documentation should declare a name +dotnet_diagnostic.SST1622.severity = error # Type parameter documentation should have text +dotnet_diagnostic.SST1623.severity = error # Property summaries should describe their accessors +dotnet_diagnostic.SST1624.severity = error # Property summary should omit a restricted set accessor +dotnet_diagnostic.SST1625.severity = error # Element documentation should not be copy-pasted +dotnet_diagnostic.SST1626.severity = error # A documentation-style comment is used where it does not document an element +dotnet_diagnostic.SST1627.severity = error # Documentation text should not be empty +dotnet_diagnostic.SST1628.severity = error # Documentation text should begin with a capital letter +dotnet_diagnostic.SST1629.severity = error # Documentation text should end with a period +dotnet_diagnostic.SST1630.severity = error # Documentation text should contain whitespace +dotnet_diagnostic.SST1631.severity = error # Documentation text should be mostly letters +dotnet_diagnostic.SST1632.severity = error # Documentation text should meet a minimum length +dotnet_diagnostic.SST1633.severity = error # Files should begin with the configured header +dotnet_diagnostic.SST1642.severity = error # Constructor summaries should begin with the standard text +dotnet_diagnostic.SST1643.severity = error # Destructor summaries should begin with the standard text +dotnet_diagnostic.SST1644.severity = error # Documentation headers should not contain blank lines +dotnet_diagnostic.SST1648.severity = error # inheritdoc should be used with inheriting elements +dotnet_diagnostic.SST1649.severity = error # The file name should match the first type name +dotnet_diagnostic.SST1651.severity = error # Placeholder documentation elements should be removed +dotnet_diagnostic.SST1653.severity = error # Keep short documentation summaries on a single line +dotnet_diagnostic.SST1654.severity = error # Extension blocks should be documented with a summary +dotnet_diagnostic.SST1655.severity = error # Extension block parameters should be documented +dotnet_diagnostic.SST1656.severity = error # Extension block type parameters should be documented +dotnet_diagnostic.SST1657.severity = error # Extension block documentation should reference a real parameter or type parameter +dotnet_diagnostic.SST1658.severity = error # Documentation text repeats a word +dotnet_diagnostic.SST1659.severity = error # A comment has no text at all +dotnet_diagnostic.SST1660.severity = error # The `` tags are not in parameter order. Code fix reorders them. Info. +dotnet_diagnostic.SST1661.severity = error # A snippet uses ``/`` mismatched to single- vs multi-line content. Code fix swaps the tag. Info. +dotnet_diagnostic.SST1662.severity = none # A thrown exception type has no `` documentation. Code fix adds the skeleton. Opt-in. +dotnet_diagnostic.SST1663.severity = none # A `//` comment before a public member reads like a summary; use `///`. Code fix converts it. Opt-in. +dotnet_diagnostic.SST1664.severity = none # A summary separates paragraphs with blank lines instead of ``. Code fix wraps them. Opt-in. + +# Concurrency and modernization +dotnet_diagnostic.SST1900.severity = error # see docs/rules/SST1900.md +dotnet_diagnostic.SST1901.severity = error # A lock targets a field or property reachable from outside the declaring type +dotnet_diagnostic.SST1902.severity = error # Do not lock on 'this', a Type, or a string +dotnet_diagnostic.SST1903.severity = error # Do not lock on a newly-created object +dotnet_diagnostic.SST1904.severity = error # A lock targets a non-readonly field +dotnet_diagnostic.SST1905.severity = error # An async method or converted delegate returns void +dotnet_diagnostic.SST2000.severity = suggestion # A null check plus throw should use ArgumentNullException.ThrowIfNull +dotnet_diagnostic.SST2001.severity = error # Use ArgumentException.ThrowIfNullOrEmpty +dotnet_diagnostic.SST2002.severity = error # Use ArgumentException.ThrowIfNullOrWhiteSpace +dotnet_diagnostic.SST2003.severity = suggestion # A disposed check should use ObjectDisposedException.ThrowIf +dotnet_diagnostic.SST2004.severity = suggestion # A range check should use an ArgumentOutOfRangeException.ThrowIf... helper +dotnet_diagnostic.SST2005.severity = error # Use the 'is' type pattern instead of comparing an 'as' cast to null +dotnet_diagnostic.SST2006.severity = error # Use the 'is not' pattern instead of negating an 'is' check +dotnet_diagnostic.SST2007.severity = error # Use declaration patterns instead of an is check followed by a cast local +dotnet_diagnostic.SST2008.severity = error # Negated pattern tests should use is-not patterns +dotnet_diagnostic.SST2009.severity = error # A catch that tests then rethrows can use a when filter +dotnet_diagnostic.SST2010.severity = error # A type reads the machine clock directly instead of through a TimeProvider +dotnet_diagnostic.SST2011.severity = error # An instant is recorded from the local clock rather than in UTC +dotnet_diagnostic.SST2012.severity = error # A GUID is constructed with the parameterless constructor instead of Guid.Empty +dotnet_diagnostic.SST2013.severity = error # An if whose entire body is another if should be merged +dotnet_diagnostic.SST2014.severity = error # A goto jumps to a label +dotnet_diagnostic.SST2015.severity = error # A ++ or -- is buried inside a larger expression +dotnet_diagnostic.SST2016.severity = error # A DateTime on a visible signature loses its offset at the boundary +dotnet_diagnostic.SST2017.severity = error # A .Date or .TimeOfDay read proves the value is only a date, or only a time of day +dotnet_diagnostic.SST2018.severity = error # A redundant null check sits beside an is type pattern + +# Modern language and library usage +dotnet_diagnostic.SST1700.severity = error # An extension block declares no members +dotnet_diagnostic.SST1701.severity = error # Two extension blocks in a type share the same receiver type +dotnet_diagnostic.SST1702.severity = error # Extension blocks in a type are separated by other members +dotnet_diagnostic.SST1703.severity = error # A classic this-parameter extension method is used where an extension block could be +dotnet_diagnostic.SST1704.severity = error # A class declaring extension blocks is not named with an Extensions suffix +dotnet_diagnostic.SST1705.severity = error # A class mixes classic extension methods with extension blocks +dotnet_diagnostic.SST1706.severity = error # An extension block targets a broad receiver type such as object or dynamic +dotnet_diagnostic.SST1707.severity = error # Extension blocks should be ordered by receiver type +dotnet_diagnostic.SST1708.severity = error # An extension method never uses its `this` receiver, so it need not be an extension. +dotnet_diagnostic.SST1709.severity = none # A method in a `*Extensions` class whose first parameter lacks `this`. Code fix converts it to an extension block. Opt-in. +dotnet_diagnostic.SST1800.severity = error # Record classes should be sealed +dotnet_diagnostic.SST1801.severity = error # A positional record parameter does not match the configured casing +dotnet_diagnostic.SST1802.severity = error # A record declares a settable rather than init-only instance property +dotnet_diagnostic.SST1803.severity = error # A record struct is not declared readonly +dotnet_diagnostic.SST1804.severity = error # A positional record has an empty `{ }` body where `;` would do. Code fix rewrites it. Info. +dotnet_diagnostic.SST2100.severity = error # An empty collection creation can use [] +dotnet_diagnostic.SST2101.severity = error # An explicit collection creation can use [...] +dotnet_diagnostic.SST2102.severity = error # A span-targeted stackalloc initializer can use a collection expression +dotnet_diagnostic.SST2103.severity = error # A collection-builder factory call can use a collection expression +dotnet_diagnostic.SST2104.severity = error # A short builder-local sequence can return a collection expression +dotnet_diagnostic.SST2105.severity = error # A literal array materialized with LINQ can use the target collection expression directly +dotnet_diagnostic.SST2200.severity = error # A single-use backing field can use the C# 14 field keyword +dotnet_diagnostic.SST2201.severity = error # A return-only switch statement can use a switch expression +dotnet_diagnostic.SST2202.severity = error # An object creation repeats an explicit target type +dotnet_diagnostic.SST2203.severity = error # An array or string index can use from-end indexing +dotnet_diagnostic.SST2204.severity = error # A string slice can use range syntax +dotnet_diagnostic.SST2205.severity = none # An enum switch statement omits named enum values — duplicate of IDE0010 (disabled: too noisy for default/fallthrough) and S131; statement switches deliberately no-op omitted values, and a default to satisfy it is rejected by SST1179/S3532. SST2206 keeps the valuable switch-expression exhaustiveness check. +dotnet_diagnostic.SST2206.severity = error # An enum switch expression omits named enum values +dotnet_diagnostic.SST2207.severity = error # A null guard and return can keep the throw in the returned expression +dotnet_diagnostic.SST2208.severity = error # An out variable can be declared at the call site +dotnet_diagnostic.SST2209.severity = none # A null-forgiving operator has no local effect +dotnet_diagnostic.SST2210.severity = error # A nullable directive repeats the current file-local state +dotnet_diagnostic.SST2211.severity = error # A nullable restore directive has no file-local state to restore +dotnet_diagnostic.SST2212.severity = error # Literal UTF-8 byte data can use a u8 string literal +dotnet_diagnostic.SST2213.severity = error # A typed pattern has an unnecessary discard designation +dotnet_diagnostic.SST2214.severity = error # A tuple temporary only feeds copied element locals +dotnet_diagnostic.SST2215.severity = error # A temporary local swaps two locals +dotnet_diagnostic.SST2216.severity = error # A tuple element name repeats the inferred name +dotnet_diagnostic.SST2217.severity = error # A manual hash-code expression can use System.HashCode.Combine +dotnet_diagnostic.SST2218.severity = error # Lambda parameter types can be omitted when the target already supplies them +dotnet_diagnostic.SST2219.severity = error # A single-expression property accessor can use an expression body +dotnet_diagnostic.SST2220.severity = error # An interpolation hole can carry the value and literal format directly +dotnet_diagnostic.SST2221.severity = error # An ignored expression value is assigned to the discard +dotnet_diagnostic.SST2222.severity = error # A local value is overwritten before it is read +dotnet_diagnostic.SST2223.severity = error # A null fallback assignment can use ??= +dotnet_diagnostic.SST2224.severity = error # An anonymous object can become a tuple literal for local value bundles +dotnet_diagnostic.SST2225.severity = error # A foreach loop hides an explicit element cast +dotnet_diagnostic.SST2226.severity = error # A cast hides an inner explicit conversion +dotnet_diagnostic.SST2227.severity = error # A post-assignment null fallback can be folded into the assigned expression +dotnet_diagnostic.SST2228.severity = error # A delegate local used only as a call target can be a local function +dotnet_diagnostic.SST2229.severity = error # see docs/rules/SST2229.md +dotnet_diagnostic.SST2230.severity = error # see docs/rules/SST2230.md +dotnet_diagnostic.SST2231.severity = error # A broad object pattern can use a direct null pattern +dotnet_diagnostic.SST2232.severity = error # nameof does not need concrete generic type arguments +dotnet_diagnostic.SST2233.severity = none # see docs/rules/SST2233.md +dotnet_diagnostic.SST2234.severity = error # Nullable should use the T? shorthand +dotnet_diagnostic.SST2235.severity = error # Capture-free local functions should be static +dotnet_diagnostic.SST2236.severity = error # Tail-position using blocks can use using declarations +dotnet_diagnostic.SST2237.severity = error # Single block-scoped namespaces can use file-scoped syntax +dotnet_diagnostic.SST2238.severity = error # Nested property patterns can use extended property syntax +dotnet_diagnostic.SST2239.severity = error # Forwarding lambdas can use method groups +dotnet_diagnostic.SST2240.severity = error # Delegate null checks can use conditional invocation +dotnet_diagnostic.SST2241.severity = error # Constructors that only store parameters can use primary-constructor storage +dotnet_diagnostic.SST2242.severity = error # Enum switch statement mappings should name every enum value or include a catch-all +dotnet_diagnostic.SST2243.severity = error # A verbatim string with escapes or line breaks can use a raw string literal +dotnet_diagnostic.SST2244.severity = error # A numeric literal's suffix is lower case +dotnet_diagnostic.SST2245.severity = error # A for loop with only a condition should be a while loop +dotnet_diagnostic.SST2246.severity = error # A chain of conditional expressions testing one value against constants can be a switch expression +dotnet_diagnostic.SST2247.severity = error # Consecutive locals copying one value's members in order can be a deconstruction +dotnet_diagnostic.SST2248.severity = error # Two constant comparisons of the same value can fold into one is-pattern +dotnet_diagnostic.SST2249.severity = error # A literal-format string.Format or literal concatenation can be an interpolated string +dotnet_diagnostic.SST2250.severity = error # A bare local assigned once by the next statement can be an initialized declaration +dotnet_diagnostic.SST2251.severity = error # A method call names type arguments that inference would supply +dotnet_diagnostic.SST2252.severity = error # A switch statement is nested inside another switch statement +dotnet_diagnostic.SST2254.severity = none # A target-typed `new()` is written where an explicit type reads more clearly; the code fix restores `new TypeName(...)`. Opt-in — the counterpart to SST2202's target-typed direction, so a team enables at most one. +dotnet_diagnostic.SST2255.severity = error # A hand-written null-or-empty string test. Code fix uses `string.IsNullOrEmpty`. +dotnet_diagnostic.SST2256.severity = error # An extension method called in static form. Code fix rewrites to instance form. Info. +dotnet_diagnostic.SST2257.severity = error # A lambda block body that is a single `return`. Code fix uses an expression body. Info. +dotnet_diagnostic.SST2258.severity = error # A redundant explicit delegate wrapper (`new EventHandler(M)`). Code fix drops it. Info. +dotnet_diagnostic.SST2259.severity = error # A stray `;` after a type declaration. Code fix removes it. Info. +dotnet_diagnostic.SST2260.severity = error # An `as` cast to a type the operand already has. Code fix removes it. Info. +dotnet_diagnostic.SST2261.severity = error # `(x && !y) +dotnet_diagnostic.SST2262.severity = error # A raw string literal whose content needs no raw syntax. Code fix demotes it. Info. +dotnet_diagnostic.SST2263.severity = error # An infinite loop whose body re-derives its stop condition. Code fix hoists the condition into the header. Info. +dotnet_diagnostic.SST2264.severity = error # A numeric literal cast to an enum. Code fix names the member. +dotnet_diagnostic.SST2265.severity = none # Consecutive fluent calls on one receiver can fold into a chain. Opt-in. +dotnet_diagnostic.SST2266.severity = none # A local read exactly once can be inlined into that use. Opt-in. +dotnet_diagnostic.SST2267.severity = none # Infinite loops written in mixed `while(true)`/`for(;;)` styles. Configurable. Opt-in. +dotnet_diagnostic.SST2268.severity = none # Inconsistent `()` on object creation with an initializer. Configurable. Opt-in. +dotnet_diagnostic.SST2269.severity = none # Inconsistent parentheses around a conditional's condition. Configurable. Opt-in. +dotnet_diagnostic.SST2270.severity = none # Inconsistent explicit-vs-implicit array-creation type. Configurable. Opt-in. +dotnet_diagnostic.SST2271.severity = none # `var`-vs-explicit local type per the configured preference. Configurable. Opt-in. +dotnet_diagnostic.SST2272.severity = none # `[Flags]` member values written as mixed decimals and shifts. Configurable. Opt-in. +dotnet_diagnostic.SST2273.severity = none # A function or loop body wraps its work in a trailing `if` that could be an early-exit guard clause. Code fix inverts it. Configurable threshold. Opt-in. +dotnet_diagnostic.SST2274.severity = error # A value assigned with `as` and then null-checked is an `is` declaration pattern in one step. Code fix rewrites it. +dotnet_diagnostic.SST2275.severity = error # A method whose block body is a single statement can use an expression body `=> expr`. Code fix rewrites it. +dotnet_diagnostic.SST2276.severity = none # A constructor whose block body is a single statement can use an expression body. Code fix rewrites it. Opt-in. +dotnet_diagnostic.SST2277.severity = none # An operator whose block body is a single `return` can use an expression body. Code fix rewrites it. Opt-in. +dotnet_diagnostic.SST2278.severity = none # A conversion operator whose block body is a single `return` can use an expression body. Code fix rewrites it. Opt-in. +dotnet_diagnostic.SST2279.severity = error # A get-only property whose getter is a single `return` can use a whole-member expression body. Code fix rewrites it. +dotnet_diagnostic.SST2280.severity = error # A get-only indexer whose getter is a single `return` can use a whole-member expression body. Code fix rewrites it. +dotnet_diagnostic.SST2281.severity = error # A local function whose block body is a single statement can use an expression body. Code fix rewrites it. +dotnet_diagnostic.SST2282.severity = error # A reference-type `ReferenceEquals` check against `null` reads as an `is null` / `is not null` pattern. Code fix rewrites it. +dotnet_diagnostic.SST2283.severity = error # A null guard that throws right before assigning the guarded value can fold into the assignment as `?? throw`. Code fix rewrites it. +# Design +dotnet_diagnostic.SST2300.severity = error # A class implements IDisposable but builds only half of the disposal pattern +dotnet_diagnostic.SST2301.severity = error # A class implementing IEquatable for itself can still be derived from +dotnet_diagnostic.SST2302.severity = error # A type overloads an operator without the rest of the set it belongs to +dotnet_diagnostic.SST2303.severity = error # A [Flags] enum's members are not distinct bit values +dotnet_diagnostic.SST2304.severity = error # An event's delegate does not have the standard (object sender, TEventArgs e) shape +dotnet_diagnostic.SST2305.severity = error # A mutable collection property declares a caller-visible setter +dotnet_diagnostic.SST2306.severity = error # A collection-returning member hands back null +dotnet_diagnostic.SST2307.severity = error # A generic method's type parameter appears in no parameter, so no caller can infer it +dotnet_diagnostic.SST2308.severity = error # An [Obsolete] attribute carries no message +dotnet_diagnostic.SST2309.severity = error # An externally visible member declares an optional parameter, so callers bake in the default +dotnet_diagnostic.SST2310.severity = error # Deprecated code is still here; remove it once its last caller is gone +dotnet_diagnostic.SST2311.severity = error # A visible const is copied into every assembly that reads it +dotnet_diagnostic.SST2312.severity = error # A type is declared outside any namespace +dotnet_diagnostic.SST2313.severity = error # An enum is stored as a type the project does not allow +dotnet_diagnostic.SST2314.severity = none # An [Obsolete] has a message but no DiagnosticId — unusable here: ObsoleteAttribute.DiagnosticId is .NET 5+, and this source is shared with net462 +dotnet_diagnostic.SST2315.severity = error # A type owns a disposable field but does not implement IDisposable +dotnet_diagnostic.SST2316.severity = error # A type declares Dispose or DisposeAsync without implementing IDisposable +dotnet_diagnostic.SST2317.severity = error # A disposable type owns a raw IntPtr without a SafeHandle or finalizer +dotnet_diagnostic.SST2318.severity = error # Two members have token-identical bodies +dotnet_diagnostic.SST2319.severity = error # An overload's optional default can never be used +dotnet_diagnostic.SST2320.severity = error # An interface inherits two interfaces that declare the same member +dotnet_diagnostic.SST2321.severity = error # Environment.Exit or Environment.FailFast is called from library code +dotnet_diagnostic.SST2322.severity = error # A non-private readonly field holds a mutable collection callers can still change +dotnet_diagnostic.SST2323.severity = error # A stateless abstract class declaring only public abstract members should be an interface +dotnet_diagnostic.SST2324.severity = error # A member is declared more accessible than its containing type +dotnet_diagnostic.SST2325.severity = error # An async method checks an argument after its first await +dotnet_diagnostic.SST2326.severity = none # An interface-typed value is narrowed to a concrete implementation — this is a high-performance core library, not strictly SOLID code, and narrowing to a known runtime type is a normal fast-path technique here: foreach over IEnumerable boxes List's struct enumerator (40 bytes per call, measured) where the indexed loop behind the type test allocates nothing +dotnet_diagnostic.SST2327.severity = error # A type tests its own runtime type against a class instead of dispatching through a virtual member +dotnet_diagnostic.SST2328.severity = error # A raw native pointer handle is exposed instead of a SafeHandle +dotnet_diagnostic.SST2329.severity = error # A `[Flags]` enum declares no zero-valued member. Code fix adds `None = 0`. +dotnet_diagnostic.SST2330.severity = error # A `[Flags]` member is a numeric literal equal to a combination of others (`All = 7`). Code fix writes `A +dotnet_diagnostic.SST2331.severity = none # An enum leaves member values implicit, so their numbers depend on declaration order. Opt-in. +dotnet_diagnostic.SST2332.severity = error # An auto-property's `private set` is only written during construction; make it get-only. +dotnet_diagnostic.SST2333.severity = none # A generic comparison/equality contract is implemented without its non-generic counterpart. Opt-in. +dotnet_diagnostic.SST2334.severity = none # A publicly visible type has no `[DebuggerDisplay]`. Opt-in. +dotnet_diagnostic.SST2335.severity = none # Parts of a partial type disagree on the `static` modifier. Opt-in. + +# Correctness +dotnet_diagnostic.SST2400.severity = error # Two arguments name each other's parameters and have been transposed +dotnet_diagnostic.SST2401.severity = error # A catch targets NullReferenceException +dotnet_diagnostic.SST2402.severity = error # An instance constructor assigns a static field of its own type +dotnet_diagnostic.SST2403.severity = error # 'this' escapes from a constructor before the object is fully built +dotnet_diagnostic.SST2404.severity = error # An iterator's argument guard does not run until the first MoveNext +dotnet_diagnostic.SST2405.severity = error # A [DebuggerDisplay] string names a member the type does not have +dotnet_diagnostic.SST2406.severity = error # A loop's stop condition reads only variables the loop never writes +dotnet_diagnostic.SST2407.severity = error # A declared event is never raised +dotnet_diagnostic.SST2408.severity = error # A StringBuilder is filled and never read +dotnet_diagnostic.SST2409.severity = error # A throw constructs a general exception type (Exception/SystemException/ApplicationException) +dotnet_diagnostic.SST2410.severity = error # A created disposable is never disposed and never leaves the method +dotnet_diagnostic.SST2411.severity = error # A for loop declares and tests a counter it never steps +dotnet_diagnostic.SST2412.severity = error # A for loop update moves the counter away from its stop condition +dotnet_diagnostic.SST2413.severity = error # A for loop condition can never be true on the first pass +dotnet_diagnostic.SST2414.severity = error # Two branches of a conditional share the same implementation +dotnet_diagnostic.SST2415.severity = error # A non-short-circuiting & or | evaluates a right operand that does work +dotnet_diagnostic.SST2416.severity = error # A modulus result on a signed type is compared directly to 1 +dotnet_diagnostic.SST2417.severity = error # A compound assignment operator is transposed (=+, =-, =!) +dotnet_diagnostic.SST2418.severity = error # The result of an immutable value's method is discarded +dotnet_diagnostic.SST2419.severity = error # A set or collection operation is performed against itself +dotnet_diagnostic.SST2420.severity = error # An IndexOf result is tested with > 0, skipping index 0 +dotnet_diagnostic.SST2421.severity = error # A write targets a readonly field of an unconstrained type parameter +dotnet_diagnostic.SST2422.severity = error # A property getter returns a different field than its setter writes +dotnet_diagnostic.SST2423.severity = error # A disposable created in a using statement is returned +dotnet_diagnostic.SST2424.severity = error # An override changes a parameter's default value +dotnet_diagnostic.SST2425.severity = error # An override drops an optional argument on its base call +dotnet_diagnostic.SST2426.severity = error # An override adds or removes params on a parameter +dotnet_diagnostic.SST2427.severity = error # A derived overload widens a parameter and hides the base overload +dotnet_diagnostic.SST2428.severity = error # A static initializer reads a static field declared later +dotnet_diagnostic.SST2429.severity = error # A setter, init, add, or remove accessor never reads value +dotnet_diagnostic.SST2430.severity = error # A serialization callback has the wrong signature +dotnet_diagnostic.SST2431.severity = error # A ToString override can return null +dotnet_diagnostic.SST2432.severity = error # GetType is called on a value that is already a System.Type +dotnet_diagnostic.SST2433.severity = error # A caller-info parameter is not last in the list +dotnet_diagnostic.SST2434.severity = error # An array is assigned through a covariant element type +dotnet_diagnostic.SST2435.severity = error # A non-object base's value-equality Equals is used as a reference-equality fast path +dotnet_diagnostic.SST2436.severity = error # An event is raised with a null sender or null args +dotnet_diagnostic.SST2437.severity = error # A generic type inherits from itself recursively +dotnet_diagnostic.SST2438.severity = error # A catch that discards its exception logs at Error or Critical without it +dotnet_diagnostic.SST2439.severity = error # An exception is passed as a log template argument instead of the exception parameter +dotnet_diagnostic.SST2440.severity = error # Log template arguments are transposed +dotnet_diagnostic.SST2441.severity = error # A log template has an empty or non-identifier placeholder +dotnet_diagnostic.SST2442.severity = error # A log template repeats a named placeholder +dotnet_diagnostic.SST2443.severity = error # An ILogger is injected or created with the wrong category type +dotnet_diagnostic.SST2444.severity = error # A regular expression pattern is invalid +dotnet_diagnostic.SST2445.severity = error # A culture-sensitive custom date or time format is used without an invariant culture +dotnet_diagnostic.SST2446.severity = error # A Stream.ReadAsync result is discarded through ConfigureAwait or a local +dotnet_diagnostic.SST2448.severity = error # A combined or opaque delegate is removed with - or -=, which strips only a contiguous run +dotnet_diagnostic.SST2449.severity = error # A lambda or anonymous-method handler is removed with -=, which never matches it +dotnet_diagnostic.SST2450.severity = error # A Debug.Assert condition performs a side effect that a release build compiles out +dotnet_diagnostic.SST2451.severity = error # Every constructor is private and no member ever creates an instance +dotnet_diagnostic.SST2452.severity = error # A [Pure] method returns void, Task, or ValueTask, so it has no observable result +dotnet_diagnostic.SST2456.severity = error # An override or new field-like event gets its own backing delegate field +dotnet_diagnostic.SST2457.severity = error # An integer Sum wrapped in unchecked still throws on overflow +dotnet_diagnostic.SST2458.severity = error # A bitwise operator is applied to an enum not declared [Flags] +dotnet_diagnostic.SST2459.severity = error # [Optional] on a ref or out parameter advertises an optionality no caller can use +dotnet_diagnostic.SST2460.severity = error # [DefaultValue] on a method or record parameter is inert +dotnet_diagnostic.SST2462.severity = error # A new member is less accessible than the inherited member it hides +dotnet_diagnostic.SST2463.severity = error # A field differs from an inherited accessible field only by case +dotnet_diagnostic.SST2464.severity = error # A mutable class declares a value-equality operator ==, so it is lost as a hash key +dotnet_diagnostic.SST2465.severity = error # A for loop body reassigns the counter or the local its condition tests +dotnet_diagnostic.SST2467.severity = error # A params overload is shadowed by a same-arity overload with a more specific last parameter +dotnet_diagnostic.SST2468.severity = error # A classic partial method is declared but never implemented, so its calls are removed +dotnet_diagnostic.SST2470.severity = error # Two string literals concatenate with no space, fusing a SQL keyword into the next token +dotnet_diagnostic.SST2472.severity = error # A type is exported for a contract it neither implements nor inherits +dotnet_diagnostic.SST2473.severity = error # A shared export part is constructed with new, bypassing the container +dotnet_diagnostic.SST2474.severity = error # A part-creation-policy attribute is applied to a type with no [Export] +dotnet_diagnostic.SST2475.severity = error # An entity's primary key is typed DateTime or DateTimeOffset +dotnet_diagnostic.SST2479.severity = error # A loop variable captured by a callback stored beyond the iteration reads its final value +dotnet_diagnostic.SST2481.severity = error # A GetHashCode override folds the base identity hash into a value hash +dotnet_diagnostic.SST2484.severity = error # A handle read through DangerousGetHandle is not reference-counted +dotnet_diagnostic.SST2485.severity = error # A NotImplementedException is left in shipped code +dotnet_diagnostic.SST2486.severity = error # An assembly is loaded by path or partial name instead of Assembly.Load +dotnet_diagnostic.SST2487.severity = error # A [ConstructorArgument] does not name a constructor parameter +dotnet_diagnostic.SST2488.severity = error # An exception is logged and rethrown, duplicating the record +dotnet_diagnostic.SST2489.severity = error # A relational comparison is decided by the operand's type rather than its value +dotnet_diagnostic.SST2490.severity = error # Adjacent try statements with identical handling should be merged +dotnet_diagnostic.SST2491.severity = error # A non-`async` method returns an awaitable from inside `using`/`try-finally`/`lock`, so the resource is torn down before the task completes. Code fix makes it `async`. +dotnet_diagnostic.SST2492.severity = error # A null-guard throws on a parameter the signature declares may be null. +dotnet_diagnostic.SST2493.severity = error # `== null`/`!= null` on an unconstrained generic `T`. Code fix uses `is null`/`is not null`. +dotnet_diagnostic.SST2494.severity = error # A `??` whose left operand is a constant null, so the right is always taken. Code fix folds it. +dotnet_diagnostic.SST2495.severity = error # A `[Flags]` combination includes an operand whose bits another already covers. Code fix removes it. +dotnet_diagnostic.SST2496.severity = error # An explicit `Dispose`/`Close` on a resource an enclosing `using` already disposes. Code fix removes it. Info. + +# Testing +dotnet_diagnostic.SST2500.severity = error # A test method contains no assertion and no expected-exception check +dotnet_diagnostic.SST2501.severity = error # An equality or identity assertion compares an expression with itself +dotnet_diagnostic.SST2502.severity = error # An equality assertion passes the constant as actual and the computed value as expected +dotnet_diagnostic.SST2503.severity = error # An equality assertion compares a value against a boolean literal +dotnet_diagnostic.SST2504.severity = error # A test fixture declares and inherits no test method +dotnet_diagnostic.SST2505.severity = error # A test method declares parameters but no data source +dotnet_diagnostic.SST2506.severity = error # A test method calls Thread.Sleep +dotnet_diagnostic.SST2507.severity = error # A test method declares its expected failure with an expected-exception attribute +dotnet_diagnostic.SST2508.severity = error # A fluent assertion is started but never completed +dotnet_diagnostic.SST2509.severity = error # A test method has a shape the runner cannot execute + +# Logging +dotnet_diagnostic.SST2600.severity = error # Application output is written through legacy Trace instead of a structured logger +dotnet_diagnostic.SST2601.severity = error # A logger field or property does not follow the logger naming convention + +# Frameworks +dotnet_diagnostic.SST2700.severity = error # An MVC route template contains a backslash; route segments are separated by `/`, so the route is unreachable. Code fix replaces `\` with `/`. +dotnet_diagnostic.SST2701.severity = error # A `[JSInvokable]` method is not public, so JavaScript interop cannot call it. Code fix makes it public. +dotnet_diagnostic.SST2702.severity = error # A `[SupplyParameterFromQuery]` property has a type the framework cannot bind from the query string, which throws at runtime. +dotnet_diagnostic.SST2703.severity = error # A routable component's route constraint (`{id:int}`) disagrees with the matching `[Parameter]` CLR type, so the route silently fails to match. +dotnet_diagnostic.SST2704.severity = error # A public action on an `[ApiController]` declares no HTTP-verb attribute, so it answers every verb and can make routing ambiguous. +dotnet_diagnostic.SST2705.severity = none # A bound model member is a non-nullable value type with no required marker, so a request that omits it binds the default with no error. Opt-in. +dotnet_diagnostic.SST2706.severity = error # A Windows Forms entry point carries neither `[STAThread]` nor `[MTAThread]`; without STA, clipboard, drag-and-drop, and common dialogs misbehave. Code fix adds `[STAThread]`. +dotnet_diagnostic.SST2707.severity = none # A fire-and-forget `Task.Run` in a controller captures the request's `HttpContext`, which is disposed when the request ends, so the background work throws `ObjectDisposedException`. Opt-in. +dotnet_diagnostic.SST2708.severity = error # A component subscribes to an event in a lifecycle method but never unsubscribes, so the event source keeps the component alive — a per-session leak on a Server circuit. +dotnet_diagnostic.SST2709.severity = error # `StateHasChanged` is called while the component is being disposed, which the renderer no longer supports and throws. +dotnet_diagnostic.SST2710.severity = error # `StateHasChanged` is called directly from a timer callback, off the renderer's dispatcher; marshal it with `InvokeAsync(StateHasChanged)`. +dotnet_diagnostic.SST2711.severity = error # A synchronous component lifecycle method is overridden as `async void`, which the framework never awaits; override the `…Async` twin returning `Task`. Code fix rewrites the signature. +dotnet_diagnostic.SST2712.severity = error # An `[Inject]`/`[CascadingParameter]` property has no setter, so the framework's reflection-based binding leaves it null. Code fix adds a setter. +dotnet_diagnostic.SST2713.severity = error # A `DotNetObjectReference.Create(this)` is passed inline and never stored, so nothing can dispose it and it leaks on the JavaScript side. + +################### +# PerformanceSharp Analyzers (PSH) +################### +performancesharp.avoid_linq_on_hot_path = true +# performancesharp.empty_string_style = pattern # PSH1204 (pattern | length | is_null_or_empty; the last two are only offered where the string is provably not null) +# performancesharp.excluded_properties = Items, Keys # PSH1017 (comma-separated; properties allowed to copy on read) +# performancesharp.include_public = false # PSH1411 (set true in an app to seal public types too; a break in a library) +dotnet_diagnostic.PSH1000.severity = error # Anonymous functions without captures should be static +dotnet_diagnostic.PSH1001.severity = error # Avoid allocating zero-length arrays (fix prefers [] on C# 12+, else Array.Empty()) +dotnet_diagnostic.PSH1002.severity = error # Empty finalizers should be removed +dotnet_diagnostic.PSH1003.severity = error # 'in' parameters should use readonly structs +dotnet_diagnostic.PSH1004.severity = error # Constant arrays passed as arguments should be hoisted +dotnet_diagnostic.PSH1005.severity = error # Structs should define equality members to avoid boxing comparisons +dotnet_diagnostic.PSH1006.severity = error # ConcurrentDictionary factories should use the lambda argument +dotnet_diagnostic.PSH1007.severity = error # Pass large readonly structs by 'in' reference (size threshold + exclusions configurable) +dotnet_diagnostic.PSH1008.severity = error # GC.SuppressFinalize does nothing for sealed finalizer-free types +dotnet_diagnostic.PSH1009.severity = error # Bound variable-length stackalloc with a constant guard +dotnet_diagnostic.PSH1010.severity = error # Clear reference-typed arrays when returning them to the pool +dotnet_diagnostic.PSH1011.severity = error # Pass state to callbacks through the state-taking overload +dotnet_diagnostic.PSH1012.severity = error # Compare type parameter values with EqualityComparer.Default +dotnet_diagnostic.PSH1013.severity = error # Expose constant UTF-8 data as a ReadOnlySpan property +dotnet_diagnostic.PSH1014.severity = error # Declare immutable structs as readonly +dotnet_diagnostic.PSH1015.severity = error # Avoid casting value types through object +dotnet_diagnostic.PSH1016.severity = error # Test enum flags with bitwise operators instead of Enum.HasFlag +dotnet_diagnostic.PSH1017.severity = error # A property allocates a copy of a collection on every read (excludable via performancesharp.PSH1017.excluded_properties) +dotnet_diagnostic.PSH1018.severity = error # A hand-written array is passed to a params parameter +dotnet_diagnostic.PSH1019.severity = error # The range indexer on an array allocates a copy; slice with AsSpan/AsMemory +dotnet_diagnostic.PSH1020.severity = error # Prefer a jagged array over a multidimensional one +dotnet_diagnostic.PSH1021.severity = error # An explicit GC.Collect or GC.WaitForPendingFinalizers forces collection the runtime tunes itself +dotnet_diagnostic.PSH1022.severity = error # A parameterless `new EventArgs()` allocates where the shared `EventArgs.Empty` singleton would serve. Code fix uses the singleton. +dotnet_diagnostic.PSH1100.severity = error # Hot-path code should avoid System.Linq.Enumerable calls +dotnet_diagnostic.PSH1101.severity = none # LINQ terminal predicate simplification is reserved for test code; production code should avoid LINQ on hot paths +dotnet_diagnostic.PSH1102.severity = none # LINQ type-filter simplification is reserved for test code; production code should avoid LINQ on hot paths +dotnet_diagnostic.PSH1103.severity = error # Prefer the collection's own count over enumerating +dotnet_diagnostic.PSH1104.severity = error # Use TryGetValue instead of ContainsKey followed by an indexer read +dotnet_diagnostic.PSH1105.severity = error # Avoid double lookups on dictionaries and sets +dotnet_diagnostic.PSH1106.severity = error # Index collections directly instead of using LINQ element access +dotnet_diagnostic.PSH1107.severity = error # Filter sequences before sorting them +dotnet_diagnostic.PSH1108.severity = error # Chain secondary sorts with ThenBy +dotnet_diagnostic.PSH1109.severity = error # Merge consecutive Where calls +dotnet_diagnostic.PSH1110.severity = error # Use the collection's own predicate methods over LINQ +dotnet_diagnostic.PSH1111.severity = error # Use Contains for membership tests +dotnet_diagnostic.PSH1112.severity = error # Seed the collection through its constructor (fix honors performancesharp.prefer_collection_expressions) +dotnet_diagnostic.PSH1113.severity = error # Sort naturally instead of ordering by the element itself +dotnet_diagnostic.PSH1114.severity = none # Freeze static lookup collections that are never mutated. Opt-in. +dotnet_diagnostic.PSH1115.severity = error # Insert-if-absent should probe the dictionary once +dotnet_diagnostic.PSH1116.severity = error # Probe string-keyed collections with a span through GetAlternateLookup +dotnet_diagnostic.PSH1117.severity = error # Ask the collection whether it is empty +dotnet_diagnostic.PSH1118.severity = error # Take the extreme element with Min/Max/MinBy/MaxBy instead of sorting +dotnet_diagnostic.PSH1119.severity = error # Check for elements with Any instead of counting them all +dotnet_diagnostic.PSH1120.severity = error # Do not materialize a sequence with ToList/ToArray just to enumerate it +dotnet_diagnostic.PSH1122.severity = error # Read a sorted set's extreme through its Min/Max property, not the LINQ extension +dotnet_diagnostic.PSH1124.severity = error # Read a linked list's end through its First/Last property, not the LINQ extension +dotnet_diagnostic.PSH1125.severity = error # Do not enumerate the same lazy sequence twice +dotnet_diagnostic.PSH1126.severity = error # Ask whether an async sequence has elements instead of counting them +dotnet_diagnostic.PSH1127.severity = error # Clear an array instead of filling it with its default +dotnet_diagnostic.PSH1200.severity = error # Compare strings without allocating case-converted copies +dotnet_diagnostic.PSH1201.severity = error # Use the char overload for single-character strings +dotnet_diagnostic.PSH1202.severity = error # Append characters as char, not single-character strings +dotnet_diagnostic.PSH1203.severity = error # Let StringBuilder do the formatting work +dotnet_diagnostic.PSH1204.severity = error # Test for empty strings by length +dotnet_diagnostic.PSH1205.severity = error # Remove interpolation that does no work +dotnet_diagnostic.PSH1206.severity = error # Do not build strings by concatenation in loops +dotnet_diagnostic.PSH1207.severity = error # Specify StringComparison for culture-sensitive string operations +dotnet_diagnostic.PSH1208.severity = error # Encode constant strings with u8 literals +dotnet_diagnostic.PSH1209.severity = error # Build transformed strings with string.Create +dotnet_diagnostic.PSH1210.severity = error # Compare UTF-8 bytes without decoding them +dotnet_diagnostic.PSH1211.severity = error # Pass values directly instead of ToString results +dotnet_diagnostic.PSH1212.severity = error # Slice with AsSpan when the call accepts a span +dotnet_diagnostic.PSH1213.severity = error # Probe repeated character sets through SearchValues +dotnet_diagnostic.PSH1214.severity = error # Append the parts of a concatenation separately, not the concatenated whole +dotnet_diagnostic.PSH1215.severity = error # Use string.Concat instead of string.Join with an empty separator +dotnet_diagnostic.PSH1216.severity = error # Use string.Equals instead of comparing string.Compare to zero +dotnet_diagnostic.PSH1217.severity = error # A sequence is copied to an array just to be read straight back +dotnet_diagnostic.PSH1218.severity = error # A substring is allocated only to search it; slice with AsSpan instead +dotnet_diagnostic.PSH1219.severity = error # Ask whether a string is blank without trimming it +dotnet_diagnostic.PSH1220.severity = error # A length argument spells out the run that reaches the end anyway +dotnet_diagnostic.PSH1221.severity = error # An IndexOf compared to 0 scans the whole string to answer a prefix test +dotnet_diagnostic.PSH1222.severity = error # Concatenate slices without materializing them +dotnet_diagnostic.PSH1223.severity = error # A reused composite format string is re-parsed on every call +dotnet_diagnostic.PSH1224.severity = error # Convert bytes to hex in one call, not by building the string twice +dotnet_diagnostic.PSH1225.severity = error # Decode bytes to a string in one call, without a throwaway char[] +dotnet_diagnostic.PSH1226.severity = error # A string's `ToCharArray()` result is only iterated, allocating a throwaway `char[]`; iterate the string directly. Code fix drops the copy. +dotnet_diagnostic.PSH1227.severity = error # A cheaper equivalent exists — `string.CompareOrdinal` over `Compare(…, Ordinal)`, `Debug.Fail` over `Debug.Assert(false, …)`. Info. Code fix rewrites the call. +dotnet_diagnostic.PSH1300.severity = error # Use System.Threading.Lock for a dedicated lock object +dotnet_diagnostic.PSH1301.severity = error # Do not wrap a single task in WhenAll or WaitAll +dotnet_diagnostic.PSH1302.severity = error # TaskCompletionSource should run continuations asynchronously +dotnet_diagnostic.PSH1303.severity = error # Do not block an async method with Thread.Sleep +dotnet_diagnostic.PSH1304.severity = error # Use PeriodicTimer instead of pacing a loop with Task.Delay +dotnet_diagnostic.PSH1305.severity = error # Enumerate a ConcurrentDictionary directly, not its Keys/Values snapshots +dotnet_diagnostic.PSH1306.severity = none # Guard one-time execution with an interlocked latch. Opt-in. +dotnet_diagnostic.PSH1307.severity = error # Access interlocked fields with Volatile +dotnet_diagnostic.PSH1308.severity = error # Return the completed task instead of Task.FromResult +dotnet_diagnostic.PSH1309.severity = none # Register cancellation callbacks without flowing the execution context. Opt-in. +dotnet_diagnostic.PSH1310.severity = error # Dispose IAsyncDisposable resources with await using in async code +dotnet_diagnostic.PSH1311.severity = error # Remove a pass-through async state machine and return the task directly +dotnet_diagnostic.PSH1312.severity = error # Return a completed task instead of null +dotnet_diagnostic.PSH1313.severity = error # A synchronous call where an async overload fits +dotnet_diagnostic.PSH1314.severity = error # Read and write streams through the memory-based overloads +dotnet_diagnostic.PSH1315.severity = error # A blocking wait on an awaitable that may not be done +dotnet_diagnostic.PSH1316.severity = error # A ValueTask is awaited in a loop or awaited after being copied +dotnet_diagnostic.PSH1400.severity = error # Use the static HashData method for one-shot hashing +dotnet_diagnostic.PSH1401.severity = error # Attribute types should be sealed +dotnet_diagnostic.PSH1402.severity = error # Use const for compile-time constants +dotnet_diagnostic.PSH1403.severity = error # Do not initialize fields to their default value +dotnet_diagnostic.PSH1404.severity = error # Get the assembly from typeof instead of a stack walk +dotnet_diagnostic.PSH1405.severity = error # Use the direct Environment APIs +dotnet_diagnostic.PSH1406.severity = error # Ask Regex for the answer directly +dotnet_diagnostic.PSH1407.severity = error # Query the dictionary, not its Keys view +dotnet_diagnostic.PSH1408.severity = error # Measure elapsed time with Stopwatch timestamps +dotnet_diagnostic.PSH1409.severity = error # Use the built-in throw helpers for argument guards +dotnet_diagnostic.PSH1410.severity = none # Mark trivial forwarders for aggressive inlining. Opt-in. +dotnet_diagnostic.PSH1411.severity = error # Seal non-public types nothing derives from so the JIT can devirtualize +dotnet_diagnostic.PSH1412.severity = error # Use Random.Shared instead of allocating a Random +dotnet_diagnostic.PSH1413.severity = error # Read the Unix epoch from the framework, not a hand-built DateTime +dotnet_diagnostic.PSH1414.severity = error # Mark members that do not touch instance state as static +dotnet_diagnostic.PSH1415.severity = error # Hold the concrete type when the concrete type is what you have +dotnet_diagnostic.PSH1416.severity = error # Cache the serializer options instead of building them per call +dotnet_diagnostic.PSH1417.severity = error # Do not compute an expensive argument for an assertion +dotnet_diagnostic.PSH1418.severity = error # An HttpClient is constructed on every call +dotnet_diagnostic.PSH1419.severity = error # A time-zone is resolved with a platform-specific id instead of the cross-platform API +dotnet_diagnostic.PSH1420.severity = error # A shareable client held in an instance field of an Azure Functions worker class is rebuilt on every invocation, leaking sockets and connections; share a static/singleton client or inject `IHttpClientFactory`. + +# ASP.NET Core - inert in this repo (no route handlers or middleware), enabled so the set stays complete +dotnet_diagnostic.PSH1500.severity = error # A minimal API handler returns Results instead of TypedResults, boxing the result +dotnet_diagnostic.PSH1501.severity = error # Middleware uses the legacy nested-delegate Use overload, allocating a per-request closure +dotnet_diagnostic.PSH1502.severity = error # A route handler returns a deferred sequence the serializer enumerates on the request thread +dotnet_diagnostic.PSH1503.severity = error # Response caching is used where server-side output caching applies +dotnet_diagnostic.PSH1505.severity = error # Exceptions are handled in an MVC exception filter instead of an IExceptionHandler +dotnet_diagnostic.PSH1506.severity = error # The HTTP request or response body is read or written synchronously (`ReadToEnd`, `Body.Read`, `Body.Write`), which blocks a thread on Kestrel and buffers the whole payload; use the async overload. Code fix awaits it when the method is already async. + +# Blazor +dotnet_diagnostic.PSH1600.severity = error # A delegate captured per iteration inside a component render loop reallocates on every render (measured ~128 B per row per render) and churns the diff; hoist it to a cached delegate or a precomputed per-item model. +dotnet_diagnostic.PSH1601.severity = error # A JavaScript-interop call is issued once per loop iteration; on Interactive Server each is a separate SignalR round-trip. Batch into a single call over the collection. +dotnet_diagnostic.PSH1602.severity = error # `StateHasChanged` is called unconditionally in `OnAfterRender`/`OnAfterRenderAsync`, scheduling another render every time — a runaway loop. Guard it with `firstRender` or a state flag. +dotnet_diagnostic.PSH1603.severity = error # A non-delegate allocation is used as a component-parameter value inside a render loop, allocating per item and forcing the child to re-render each pass. Sibling of PSH1600. + +################### +# SecuritySharp Analyzers (SES) +################### +# Every rule is raised to error, including the three that ship at suggestion (SES1403, SES1506, +# SES1605). Security rules only ever suggest an API they can resolve in the compilation and report +# local shapes only - there is no interprocedural taint tracking, so the taint-flow CA rules stay on. +# securitysharp.SES1003.iterations = 100000 # minimum accepted PBKDF2 iteration count +# securitysharp.SES1403.maxdepth = 64 # highest accepted System.Text.Json MaxDepth + +# Cryptography +dotnet_diagnostic.SES1001.severity = error # AEAD encryption must not use a constant or reused nonce +dotnet_diagnostic.SES1002.severity = error # Password-based key derivation must not use a constant or predictable salt +dotnet_diagnostic.SES1003.severity = error # Password-based key derivation must use a sufficient iteration count +dotnet_diagnostic.SES1004.severity = error # A secret must not be produced from Guid.NewGuid() +dotnet_diagnostic.SES1005.severity = error # Compare secret values in constant time +dotnet_diagnostic.SES1006.severity = error # A Data Protection key ring is persisted without a ProtectKeysWith call, so keys sit unencrypted at rest +dotnet_diagnostic.SES1007.severity = error # A cryptographic primitive is implemented by hand instead of using a vetted platform algorithm +dotnet_diagnostic.SES1008.severity = error # An XML signature is verified with the no-key CheckSignature overload, trusting the document's own KeyInfo +dotnet_diagnostic.SES1009.severity = error # A password is stored without a slow, salted key-derivation function + +# Transport +dotnet_diagnostic.SES1102.severity = error # Do not accept any server certificate +dotnet_diagnostic.SES1104.severity = error # Certificate-chain validation must not be deliberately weakened +dotnet_diagnostic.SES1105.severity = error # Bearer and OpenID Connect metadata must not be retrieved over plain HTTP outside development +dotnet_diagnostic.SES1106.severity = error # Do not send HttpClient requests to a cleartext http URL +dotnet_diagnostic.SES1107.severity = error # A SQL connection string weakens transport security via TrustServerCertificate or a disabled Encrypt +dotnet_diagnostic.SES1108.severity = error # A custom server-certificate validation callback unconditionally returns true, so any certificate is trusted + +# Secrets +dotnet_diagnostic.SES1201.severity = error # Do not hard-code secrets in source +dotnet_diagnostic.SES1202.severity = error # Do not hard-code a credential value +dotnet_diagnostic.SES1203.severity = error # A connection string names a user but supplies an empty or missing password + +# Injection +dotnet_diagnostic.SES1301.severity = error # Do not build a process command line from non-constant string parts +dotnet_diagnostic.SES1302.severity = error # A shell-executed process must not use a non-constant FileName +dotnet_diagnostic.SES1303.severity = error # Regular-expression pattern must not be built from non-constant data +dotnet_diagnostic.SES1304.severity = error # An archive entry name must not build a write path without a containment check +dotnet_diagnostic.SES1305.severity = error # Do not build a storage path from an uploaded file name +dotnet_diagnostic.SES1306.severity = error # Do not compile or execute non-constant C# via the scripting API +dotnet_diagnostic.SES1307.severity = error # Path.GetTempFileName creates a predictable, world-readable temporary file +dotnet_diagnostic.SES1308.severity = error # A file or directory is created group- or world-writable +dotnet_diagnostic.SES1309.severity = error # An XSLT stylesheet is loaded with embedded script enabled +dotnet_diagnostic.SES1310.severity = error # A directory bind is performed without authenticating + +# Serialization +dotnet_diagnostic.SES1401.severity = error # A type resolved from non-constant data must not be instantiated or deserialized +dotnet_diagnostic.SES1402.severity = error # Do not load an assembly from raw bytes or a non-constant location +dotnet_diagnostic.SES1403.severity = error # JSON deserialization depth limit must stay within a safe ceiling +dotnet_diagnostic.SES1404.severity = error # A type is instantiated by name from a non-constant Activator typeName +dotnet_diagnostic.SES1405.severity = error # MessagePack typeless deserialization reconstructs whatever type the payload names +dotnet_diagnostic.SES1406.severity = warning # Reflection must not reach non-public members via BindingFlags.NonPublic (opt-in; replaces S3011) + +# Web hardening +dotnet_diagnostic.SES1501.severity = error # A CORS policy must not allow credentials together with any origin +dotnet_diagnostic.SES1502.severity = error # A CORS origin predicate must not unconditionally allow every origin +dotnet_diagnostic.SES1503.severity = error # JWT signature verification must not be disabled on TokenValidationParameters +dotnet_diagnostic.SES1504.severity = error # A cookie with SameSite=None must be marked Secure +dotnet_diagnostic.SES1505.severity = error # The request body size limit must not be removed +dotnet_diagnostic.SES1506.severity = error # The developer exception page must be guarded by a development-environment check +dotnet_diagnostic.SES1507.severity = error # AllowAnonymous and Authorize on the same declaration conflict +dotnet_diagnostic.SES1508.severity = error # A validation method must not fail open by returning success from a catch +dotnet_diagnostic.SES1509.severity = error # A backtracking-prone constant regex runs without a match timeout or NonBacktracking +dotnet_diagnostic.SES1510.severity = error # A controller redirects to a non-constant URL, allowing an open redirect +dotnet_diagnostic.SES1511.severity = error # The forwarded-headers trust boundary is cleared, letting proxies spoof the client IP +dotnet_diagnostic.SES1512.severity = error # Sensitive framework diagnostics are enabled without a development-environment guard +dotnet_diagnostic.SES1513.severity = error # An AuthorizeAsync result is discarded, so the guarded operation runs regardless +dotnet_diagnostic.SES1514.severity = error # OpenID Connect protections (PKCE, state, nonce) are disabled +dotnet_diagnostic.SES1515.severity = error # A Content-Security-Policy value disables its own protection + +# AI trust boundaries +dotnet_diagnostic.SES1601.severity = error # An LLM system prompt must be a constant, trusted template +dotnet_diagnostic.SES1602.severity = error # Do not route AI model output into a process, file, or raw SQL sink +dotnet_diagnostic.SES1603.severity = error # An AI tool declared read-only or non-destructive must not call a state-changing API +dotnet_diagnostic.SES1604.severity = error # Prompt-template input encoding must not be disabled +dotnet_diagnostic.SES1605.severity = error # AI instrumentation must not enable sensitive-data capture +dotnet_diagnostic.SES1606.severity = error # Do not fetch model weights over cleartext HTTP + +# Web UI trust boundaries +dotnet_diagnostic.SES1701.severity = error # Raw HTML is rendered from a non-constant value (`MarkupString`/`AddMarkupContent`), bypassing automatic encoding — an XSS risk. Sanitizer allow-list via `securitysharp.SES1701.sanitizers`. +dotnet_diagnostic.SES1702.severity = error # A JavaScript-interop call targets a script-evaluation primitive (`eval`, `Function`, `document.write`), turning interop into a script-injection channel. +dotnet_diagnostic.SES1703.severity = error # `[Authorize]` on a non-routable component enforces nothing — authorization runs as a routing concern. Exempt types via `securitysharp.SES1703.exempt_types`. +dotnet_diagnostic.SES1704.severity = error # `IHttpContextAccessor` or a cascading `HttpContext` is used in an interactively-rendered component, where it is null or frozen at circuit start. +dotnet_diagnostic.SES1705.severity = error # `NavigationManager.NavigateTo` is called with a target that is not a verified relative URL — an open-redirect risk. Validator allow-list via `securitysharp.SES1705.validators`. +dotnet_diagnostic.SES1706.severity = error # An uploaded file is read with an unbounded or client-chosen size limit, letting an attacker fill server memory. Threshold via `securitysharp.SES1706.max_bytes`. +dotnet_diagnostic.SES1707.severity = error # A secret-shaped literal appears in code reachable as WebAssembly, which downloads to the browser in full — guaranteed disclosure. +dotnet_diagnostic.SES1708.severity = error # `CircuitOptions.DetailedErrors` is enabled, shipping server exception detail to every connected client. +dotnet_diagnostic.SES1709.severity = error # `SerializeAllClaims` serializes every claim into client-readable WebAssembly authentication state, exposing internal ids, tokens, and PII. +dotnet_diagnostic.SES1710.severity = error # Antiforgery validation is disabled on a form (`[RequireAntiforgeryToken(required: false)]`), removing CSRF protection. + + +################### +# Microsoft.CodeAnalysis.PublicApiAnalyzers (RS) +################### +# Public API surface tracking +dotnet_diagnostic.RS0016.severity = error # public symbol missing from the PublicAPI baseline +dotnet_diagnostic.RS0017.severity = error # PublicAPI baseline entry no longer in source + +################### +# Microsoft.NET.ILLink.Analyzers (IL) +################### +# Trimming # See: https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trim-warnings/ -################### dotnet_diagnostic.IL2001.severity = error # Type in UnreferencedCode attribute doesn't have matching RequiresUnreferencedCode dotnet_diagnostic.IL2002.severity = error # Method with RequiresUnreferencedCode called from code without that attribute dotnet_diagnostic.IL2003.severity = error # RequiresUnreferencedCode attribute is only supported on methods @@ -1439,10 +2134,8 @@ dotnet_diagnostic.IL2117.severity = error # Methods with DynamicallyAccessedMemb dotnet_diagnostic.IL2122.severity = error # Reflection call to method with UnreferencedCode attribute cannot be statically analyzed dotnet_diagnostic.IL2123.severity = error # DynamicallyAccessedMembers on method or parameter doesn't match overridden member -################### -# AOT Analyzer Warnings (IL3xxx) +# Native AOT # See: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/warnings/ -################### dotnet_diagnostic.IL3050.severity = error # Using member annotated with RequiresDynamicCode dotnet_diagnostic.IL3051.severity = error # RequiresDynamicCode attribute is only supported on methods and constructors dotnet_diagnostic.IL3052.severity = error # RequiresDynamicCode attribute on type is not supported @@ -1452,490 +2145,473 @@ dotnet_diagnostic.IL3055.severity = error # MakeGenericType on non-supported typ dotnet_diagnostic.IL3056.severity = error # MakeGenericMethod on non-supported method requires dynamic code dotnet_diagnostic.IL3057.severity = error # Reflection access to generic parameter requires dynamic code - ################### -# SonarAnalyzer (Sxxxx) - Blocker Bug +# SonarAnalyzer.CSharp (S) ################### -dotnet_diagnostic.S1048.severity = error # Finalizers should not throw exceptions +# Repository suppressions +dotnet_diagnostic.S1075.severity = none # Hardcoded URI — canonical SourceLink hosts are the point +dotnet_diagnostic.S2436.severity = none # Too many generic parameters — needed for the projector overload +dotnet_diagnostic.S4036.severity = none # PATH-relative process spawn — benchmark only, trusted env +dotnet_diagnostic.S8969.severity = none # Nullability inference is inconsistent across the repository's target frameworks + +# Blocker bugs +dotnet_diagnostic.S1048.severity = none # Finalizers should not throw exceptions — covered by SST1485 dotnet_diagnostic.S2190.severity = none # Loops and recursions should not be infinite dotnet_diagnostic.S2275.severity = none # Composite format strings should not lead to unexpected behavior at runtime - DUPLICATE CA2241 -dotnet_diagnostic.S2857.severity = error # SQL keywords should be delimited by whitespace -dotnet_diagnostic.S2930.severity = error # "IDisposables" should be disposed -dotnet_diagnostic.S2931.severity = error # Classes with "IDisposable" members should implement "IDisposable" -dotnet_diagnostic.S3464.severity = error # Type inheritance should not be recursive -dotnet_diagnostic.S3869.severity = error # "SafeHandle.DangerousGetHandle" should not be called -dotnet_diagnostic.S3889.severity = error # "Thread.Resume" and "Thread.Suspend" should not be used -dotnet_diagnostic.S4159.severity = error # Classes should implement their "ExportAttribute" interfaces - -################### -# SonarAnalyzer (Sxxxx) - Critical Bug -################### -dotnet_diagnostic.S2551.severity = error # Shared resources should not be used for locking -dotnet_diagnostic.S2952.severity = error # Classes should "Dispose" of members from the classes' own "Dispose" methods -dotnet_diagnostic.S3449.severity = error # Right operands of shift operators should be integers -dotnet_diagnostic.S4275.severity = error # Getters and setters should access the expected fields -dotnet_diagnostic.S4277.severity = error # "Shared" parts should not be created with "new" -dotnet_diagnostic.S4583.severity = error # Calls to delegate's method "BeginInvoke" should be paired with calls to "EndInvoke" -dotnet_diagnostic.S4586.severity = error # Non-async "Task/Task" methods should not return null -dotnet_diagnostic.S5856.severity = error # Regular expressions should be syntactically valid -dotnet_diagnostic.S6674.severity = error # Log message template should be syntactically correct - -################### -# SonarAnalyzer (Sxxxx) - Major Bug -################### -dotnet_diagnostic.S1244.severity = error # Floating point numbers should not be tested for equality -dotnet_diagnostic.S1656.severity = error # Variables should not be self-assigned -dotnet_diagnostic.S1751.severity = error # Loops with at most one iteration should be refactored -dotnet_diagnostic.S1764.severity = error # Identical expressions should not be used on both sides of operators -dotnet_diagnostic.S1848.severity = error # Objects should not be created to be dropped immediately without being used -dotnet_diagnostic.S1862.severity = error # Related "if/else if" statements should not have the same condition -dotnet_diagnostic.S2114.severity = error # Collections should not be passed as arguments to their own methods -dotnet_diagnostic.S2123.severity = error # Values should not be uselessly incremented -dotnet_diagnostic.S2201.severity = error # Methods without side effects should not have their return values ignored -dotnet_diagnostic.S2225.severity = error # "ToString()" method should not return null -dotnet_diagnostic.S2251.severity = error # A "for" loop update clause should move the counter in the right direction -dotnet_diagnostic.S2252.severity = error # For-loop conditions should be true at least once -dotnet_diagnostic.S2445.severity = error # Blocks should be synchronized on read-only fields -dotnet_diagnostic.S2688.severity = error # "NaN" should not be used in comparisons -dotnet_diagnostic.S2757.severity = error # Non-existent operators like "=+" should not be used -dotnet_diagnostic.S2761.severity = error # Doubled prefix operators "!!" and "~~" should not be used -dotnet_diagnostic.S2995.severity = error # "Object.ReferenceEquals" should not be used for value types -dotnet_diagnostic.S2996.severity = error # "ThreadStatic" fields should not be initialized -dotnet_diagnostic.S2997.severity = error # "IDisposables" created in a "using" statement should not be returned -dotnet_diagnostic.S3005.severity = error # "ThreadStatic" should not be used on non-static fields -dotnet_diagnostic.S3168.severity = error # "async" methods should not return "void" -dotnet_diagnostic.S3172.severity = error # Delegates should not be subtracted -dotnet_diagnostic.S3244.severity = error # Anonymous delegates should not be used to unsubscribe from Events -dotnet_diagnostic.S3249.severity = error # Classes directly extending "object" should not call "base" in "GetHashCode" or "Equals" -dotnet_diagnostic.S3263.severity = error # Static fields should appear in the order they must be initialized -dotnet_diagnostic.S3343.severity = error # Caller information parameters should come at the end of the parameter list -dotnet_diagnostic.S3346.severity = error # Expressions used in "Debug.Assert" should not produce side effects -dotnet_diagnostic.S3453.severity = error # Classes should not have only "private" constructors -dotnet_diagnostic.S3466.severity = error # Optional parameters should be passed to "base" calls -dotnet_diagnostic.S3598.severity = error # One-way "OperationContract" methods should have "void" return type -dotnet_diagnostic.S3603.severity = error # Methods with "Pure" attribute should return a value -dotnet_diagnostic.S3610.severity = error # Nullable type comparison should not be redundant -dotnet_diagnostic.S3903.severity = error # Types should be defined in named namespaces -dotnet_diagnostic.S3923.severity = error # All branches in a conditional structure should not have exactly the same implementation -dotnet_diagnostic.S3926.severity = error # Deserialization methods should be provided for "OptionalField" members -dotnet_diagnostic.S3927.severity = error # Serialization event handlers should be implemented correctly -dotnet_diagnostic.S3981.severity = error # Collection sizes and array length comparisons should make sense -dotnet_diagnostic.S3984.severity = error # Exceptions should not be created without being thrown -dotnet_diagnostic.S4143.severity = error # Collection elements should not be replaced unconditionally -dotnet_diagnostic.S4210.severity = error # Windows Forms entry points should be marked with STAThread -dotnet_diagnostic.S4260.severity = error # "ConstructorArgument" parameters should exist in constructors -dotnet_diagnostic.S4428.severity = error # "PartCreationPolicyAttribute" should be used with "ExportAttribute" -dotnet_diagnostic.S6507.severity = error # Blocks should not be synchronized on local variables -dotnet_diagnostic.S6677.severity = error # Message template placeholders should be unique -dotnet_diagnostic.S6797.severity = error # Blazor query parameter type should be supported -dotnet_diagnostic.S6798.severity = error # [JSInvokable] attribute should only be used on public methods -dotnet_diagnostic.S6800.severity = error # Component parameter type should match the route parameter type constraint -dotnet_diagnostic.S6930.severity = error # Backslash should be avoided in route templates - -################### -# SonarAnalyzer (Sxxxx) - Minor Bug -################### +dotnet_diagnostic.S2857.severity = none # SQL keywords should be delimited by whitespace — covered by SST2470 +dotnet_diagnostic.S2930.severity = none # "IDisposables" should be disposed — covered by SST2410 +dotnet_diagnostic.S2931.severity = none # Classes with "IDisposable" members should implement "IDisposable" — covered by SST2315 +dotnet_diagnostic.S3464.severity = none # Type inheritance should not be recursive — covered by SST2437 +dotnet_diagnostic.S3869.severity = none # "SafeHandle.DangerousGetHandle" should not be called -> replaced by SST2484 +dotnet_diagnostic.S3889.severity = none # "Thread.Resume" and "Thread.Suspend" should not be used -> replaced by obsolete or compiler +dotnet_diagnostic.S4159.severity = none # Classes should implement their "ExportAttribute" interfaces — covered by SST2472 + +# Critical bugs +dotnet_diagnostic.S2551.severity = none # Shared resources should not be used for locking — covered by SST1902 +dotnet_diagnostic.S2952.severity = none # Classes should "Dispose" of members from the classes' own "Dispose" methods -> replaced by SST2315 +dotnet_diagnostic.S3449.severity = none # Right operands of shift operators should be integers -> replaced by SST1478 +dotnet_diagnostic.S4275.severity = none # Getters and setters should access the expected fields — covered by SST2422 +dotnet_diagnostic.S4277.severity = none # "Shared" parts should not be created with "new" — covered by SST2473 +dotnet_diagnostic.S4583.severity = none # Calls to delegate's method "BeginInvoke" should be paired with calls to "EndInvoke" -> replaced by obsolete (APM BeginInvoke/EndInvoke) +dotnet_diagnostic.S4586.severity = none # Non-async "Task/Task" methods should not return null — covered by PSH1312 +dotnet_diagnostic.S5856.severity = none # Regular expressions should be syntactically valid — covered by SST2444 +dotnet_diagnostic.S6674.severity = none # Log message template should be syntactically correct — covered by SST2441 + +# Major bugs +dotnet_diagnostic.S1244.severity = none # Floating point numbers should not be tested for equality — covered by SST1473 +dotnet_diagnostic.S1656.severity = none # Variables should not be self-assigned — covered by SST1189 +dotnet_diagnostic.S1751.severity = none # Loops with at most one iteration should be refactored - covered by SST1444 +dotnet_diagnostic.S1764.severity = none # Identical expressions should not be used on both sides of operators — covered by SST1474 +dotnet_diagnostic.S1848.severity = none # Objects should not be created to be dropped immediately without being used -> replaced by SST1480 +dotnet_diagnostic.S1862.severity = none # Related "if/else if" statements should not have the same condition — covered by SST1475 +dotnet_diagnostic.S2114.severity = none # Collections should not be passed as arguments to their own methods — covered by SST2419 +dotnet_diagnostic.S2123.severity = none # Values should not be uselessly incremented -> replaced by SST2222 +dotnet_diagnostic.S2201.severity = none # Methods without side effects should not have their return values ignored — covered by SST2418 +dotnet_diagnostic.S2225.severity = none # "ToString()" method should not return null — covered by SST2431 +dotnet_diagnostic.S2251.severity = none # A "for" loop update clause should move the counter in the right direction — covered by SST2412 +dotnet_diagnostic.S2252.severity = none # For-loop conditions should be true at least once — covered by SST2413 +dotnet_diagnostic.S2445.severity = none # Blocks should be synchronized on read-only fields — covered by SST1904 +dotnet_diagnostic.S2688.severity = none # "NaN" should not be used in comparisons — covered by SST1473 +dotnet_diagnostic.S2757.severity = none # Non-existent operators like "=+" should not be used — covered by SST2417 +dotnet_diagnostic.S2761.severity = none # Doubled prefix operators "!!" and "~~" should not be used — covered by SST1190 +dotnet_diagnostic.S2995.severity = none # "Object.ReferenceEquals" should not be used for value types -> replaced by CA2013 +dotnet_diagnostic.S2996.severity = none # "ThreadStatic" fields should not be initialized -> replaced by CA2019 +dotnet_diagnostic.S2997.severity = none # "IDisposables" created in a "using" statement should not be returned — covered by SST2423 +dotnet_diagnostic.S3005.severity = none # "ThreadStatic" should not be used on non-static fields -> replaced by CA2259 +dotnet_diagnostic.S3168.severity = none # "async" methods should not return "void" — covered by SST1905 +dotnet_diagnostic.S3172.severity = none # Delegates should not be subtracted — covered by SST2448 +dotnet_diagnostic.S3244.severity = none # Anonymous delegates should not be used to unsubscribe from Events — covered by SST2449 +dotnet_diagnostic.S3249.severity = none # Covered by SST1447 (canonical) +dotnet_diagnostic.S3263.severity = none # Static fields should appear in the order they must be initialized — covered by SST2428 +dotnet_diagnostic.S3343.severity = none # Caller information parameters should come at the end of the parameter list — covered by SST2433 +dotnet_diagnostic.S3346.severity = none # Expressions used in "Debug.Assert" should not produce side effects — covered by SST2450 +dotnet_diagnostic.S3453.severity = none # Classes should not have only "private" constructors — covered by SST2451 +dotnet_diagnostic.S3466.severity = none # Optional parameters should be passed to "base" calls — covered by SST2425 +dotnet_diagnostic.S3598.severity = none # One-way "OperationContract" methods should have "void" return type -> replaced by obsolete (WCF) +dotnet_diagnostic.S3603.severity = none # Methods with "Pure" attribute should return a value — covered by SST2452 +dotnet_diagnostic.S3610.severity = none # Nullable type comparison should not be redundant -> replaced by compiler CS0472 +dotnet_diagnostic.S3903.severity = none # Types should be defined in named namespaces — covered by SST2312 +dotnet_diagnostic.S3923.severity = none # All branches in a conditional structure should not have exactly the same implementation — covered by SST1476 +dotnet_diagnostic.S3926.severity = none # Deserialization methods should be provided for "OptionalField" members -> replaced by obsolete (legacy binary serialization) +dotnet_diagnostic.S3927.severity = none # Serialization event handlers should be implemented correctly — covered by SST2430 +dotnet_diagnostic.S3981.severity = none # Collection sizes and array length comparisons should make sense — covered by SST1479 +dotnet_diagnostic.S3984.severity = none # Exceptions should not be created without being thrown — covered by SST1480 +dotnet_diagnostic.S4143.severity = none # Collection elements should not be replaced unconditionally — covered by SST1487 +dotnet_diagnostic.S4210.severity = none # Windows Forms entry points should be marked with STAThread -> replaced by SST2706 +dotnet_diagnostic.S4260.severity = none # "ConstructorArgument" parameters should exist in constructors -> replaced by SST2487 +dotnet_diagnostic.S4428.severity = none # "PartCreationPolicyAttribute" should be used with "ExportAttribute" — covered by SST2474 +dotnet_diagnostic.S6507.severity = none # Blocks should not be synchronized on local variables — covered by SST1903 +dotnet_diagnostic.S6677.severity = none # Message template placeholders should be unique — covered by SST2442 +dotnet_diagnostic.S6797.severity = none # Blazor query parameter type should be supported -> replaced by SST2702 +dotnet_diagnostic.S6798.severity = none # [JSInvokable] attribute should only be used on public methods -> replaced by SST2701 +dotnet_diagnostic.S6800.severity = none # Component parameter type should match the route parameter type constraint -> replaced by SST2703 +dotnet_diagnostic.S6930.severity = none # Backslash should be avoided in route templates -> replaced by SST2700 + +# Minor bugs dotnet_diagnostic.S1206.severity = none # "Equals(Object)" and "GetHashCode()" should be overridden in pairs - DUPLICATE CA2218 -dotnet_diagnostic.S1226.severity = error # Method parameters, caught exceptions and foreach variables' initial values should not be ignored -dotnet_diagnostic.S2183.severity = error # Integral numbers should not be shifted by zero or more than their number of bits-1 -dotnet_diagnostic.S2184.severity = error # Results of integer division should not be assigned to floating point variables -dotnet_diagnostic.S2328.severity = error # "GetHashCode" should not reference mutable fields -dotnet_diagnostic.S2345.severity = error # Flags enumerations should explicitly initialize all their members -dotnet_diagnostic.S2674.severity = error # The length returned from a stream read should be checked -dotnet_diagnostic.S2934.severity = error # Property assignments should not be made for "readonly" fields not constrained to reference types -dotnet_diagnostic.S2955.severity = error # Generic parameters not constrained to reference types should not be compared to "null" -dotnet_diagnostic.S3363.severity = error # Date and time should not be used as a type for primary keys -dotnet_diagnostic.S3397.severity = error # "base.Equals" should not be used to check for reference equality in "Equals" if "base" is not "object" -dotnet_diagnostic.S3456.severity = error # "string.ToCharArray()" and "ReadOnlySpan.ToArray()" should not be called redundantly -dotnet_diagnostic.S3887.severity = error # Mutable, non-private fields should not be "readonly" - -################### -# SonarAnalyzer (Sxxxx) - Blocker Vulnerability -################### -dotnet_diagnostic.S2115.severity = error # A secure password should be used when connecting to a database -dotnet_diagnostic.S2755.severity = error # XML parsers should not be vulnerable to XXE attacks -dotnet_diagnostic.S3884.severity = error # "CoSetProxyBlanket" and "CoInitializeSecurity" should not be used -dotnet_diagnostic.S6418.severity = error # Secrets should not be hard-coded - -################### -# SonarAnalyzer (Sxxxx) - Critical Vulnerability -################### -dotnet_diagnostic.S4423.severity = error # Weak SSL/TLS protocols should not be used -dotnet_diagnostic.S4426.severity = error # Cryptographic keys should be robust -dotnet_diagnostic.S4433.severity = error # LDAP connections should be authenticated -dotnet_diagnostic.S4830.severity = error # Server certificates should be verified during SSL/TLS connections -dotnet_diagnostic.S5344.severity = error # Passwords should not be stored in plaintext or with a fast hashing algorithm -dotnet_diagnostic.S5445.severity = error # Insecure temporary file creation methods should not be used -dotnet_diagnostic.S5542.severity = error # Encryption algorithms should be used with secure mode and padding scheme -dotnet_diagnostic.S5547.severity = error # Cipher algorithms should be robust -dotnet_diagnostic.S5659.severity = error # JWT should be signed and verified with strong cipher algorithms - -################### -# SonarAnalyzer (Sxxxx) - Major Vulnerability -################### -dotnet_diagnostic.S2068.severity = error # Credentials should not be hard-coded -dotnet_diagnostic.S2612.severity = error # File permissions should not be set to world-accessible values -dotnet_diagnostic.S4211.severity = error # Members should not have conflicting transparency annotations -dotnet_diagnostic.S4212.severity = error # Serialization constructors should be secured -dotnet_diagnostic.S6377.severity = error # XML signatures should be validated securely -dotnet_diagnostic.S7039.severity = error # Content Security Policies should be restrictive - -################### -# SonarAnalyzer (Sxxxx) - Blocker Code Smell -################### -dotnet_diagnostic.S1147.severity = error # Exit methods should not be called +dotnet_diagnostic.S1226.severity = none # Method parameters, caught exceptions and foreach variables' initial values should not be ignored +dotnet_diagnostic.S2183.severity = none # Integral numbers should not be shifted by zero or more than their number of bits-1 — covered by SST1478 +dotnet_diagnostic.S2184.severity = none # Results of integer division should not be assigned to floating point variables — covered by SST1477 +dotnet_diagnostic.S2328.severity = none # "GetHashCode" should not reference mutable fields — covered by SST1482 +dotnet_diagnostic.S2345.severity = none # Flags enumerations should explicitly initialize all their members — covered by SST2303 +dotnet_diagnostic.S2674.severity = none # The length returned from a stream read should be checked — covered by SST2446 +dotnet_diagnostic.S2934.severity = none # Property assignments should not be made for "readonly" fields not constrained to reference types — covered by SST2421 +dotnet_diagnostic.S2955.severity = none # Generic parameters not constrained to reference types should not be compared to "null" -> replaced by compiler CS0019/CS0037 +dotnet_diagnostic.S3363.severity = none # Date and time should not be used as a type for primary keys — covered by SST2475 +dotnet_diagnostic.S3397.severity = none # "base.Equals" should not be used to check for reference equality in "Equals" if "base" is not "object" — covered by SST2435 +dotnet_diagnostic.S3456.severity = none # "string.ToCharArray()" and "ReadOnlySpan.ToArray()" should not be called redundantly — covered by PSH1217 +dotnet_diagnostic.S3887.severity = none # Mutable, non-private fields should not be "readonly" — covered by SST2322 + +# Blocker vulnerabilities +dotnet_diagnostic.S2115.severity = none # A secure password should be used when connecting to a database -> replaced by SES1203 +dotnet_diagnostic.S2755.severity = none # XML parsers should not be vulnerable to XXE attacks -> replaced by CA3075 +dotnet_diagnostic.S3884.severity = none # "CoSetProxyBlanket" and "CoInitializeSecurity" should not be used -> replaced by obsolete (COM interop security) +dotnet_diagnostic.S6418.severity = none # Secrets should not be hard-coded — covered by SES1201 + +# Critical vulnerabilities +dotnet_diagnostic.S4423.severity = none # Weak SSL/TLS protocols should not be used -> replaced by CA5397/CA5398 +dotnet_diagnostic.S4426.severity = none # Cryptographic keys should be robust -> replaced by CA5385 (RSA) / CA5384 (DSA) +dotnet_diagnostic.S4433.severity = none # LDAP connections should be authenticated -> replaced by SES1310 +dotnet_diagnostic.S4830.severity = none # Server certificates should be verified during SSL/TLS connections -> replaced by SES1102 or SES1108 +dotnet_diagnostic.S5344.severity = none # Passwords should not be stored in plaintext or with a fast hashing algorithm -> replaced by SES1009 +dotnet_diagnostic.S5445.severity = none # Insecure temporary file creation methods should not be used -> replaced by SES1307 +dotnet_diagnostic.S5542.severity = none # Encryption algorithms should be used with secure mode and padding scheme -> replaced by CA5358 +dotnet_diagnostic.S5547.severity = none # Cipher algorithms should be robust -> replaced by CA5351 +dotnet_diagnostic.S5659.severity = none # JWT should be signed and verified with strong cipher algorithms -> replaced by SES1503 + +# Major vulnerabilities +dotnet_diagnostic.S2068.severity = none # Credentials should not be hard-coded -> replaced by SES1201 +dotnet_diagnostic.S2612.severity = none # File permissions should not be set to world-accessible values -> replaced by SES1308 +dotnet_diagnostic.S4211.severity = none # Members should not have conflicting transparency annotations -> replaced by obsolete (Code Access Security) +dotnet_diagnostic.S4212.severity = none # Serialization constructors should be secured -> replaced by obsolete (Code Access Security) +dotnet_diagnostic.S6377.severity = none # XML signatures should be validated securely -> replaced by SES1008 +dotnet_diagnostic.S7039.severity = none # Content Security Policies should be restrictive -> replaced by SES1515 + +# Blocker code smells +dotnet_diagnostic.S1147.severity = none # Exit methods should not be called — covered by SST2321 dotnet_diagnostic.S1451.severity = none # Track lack of copyright and license headers -dotnet_diagnostic.S2178.severity = error # Short-circuit logic should be used in boolean contexts -dotnet_diagnostic.S2187.severity = error # Test classes should contain at least one test case -dotnet_diagnostic.S2306.severity = error # "async" and "await" should not be used as identifiers +dotnet_diagnostic.S2178.severity = none # Short-circuit logic should be used in boolean contexts — covered by SST2415 +dotnet_diagnostic.S2187.severity = none # Test classes should contain at least one test case — covered by SST2504 +dotnet_diagnostic.S2306.severity = none # "async" and "await" should not be used as identifiers -> replaced by compiler (contextual keyword) dotnet_diagnostic.S2368.severity = none # Public methods should not have multidimensional array parameters — jagged arrays are the chosen layout for hot-path lookup tables -dotnet_diagnostic.S2387.severity = error # Child class fields should not shadow parent class fields -dotnet_diagnostic.S2437.severity = error # Unnecessary bit operations should not be performed -dotnet_diagnostic.S2699.severity = error # Tests should include assertions -dotnet_diagnostic.S2953.severity = error # Methods named "Dispose" should implement "IDisposable.Dispose" -dotnet_diagnostic.S2970.severity = error # Assertions should be complete -dotnet_diagnostic.S3060.severity = error # "is" should not be used with "this" -dotnet_diagnostic.S3237.severity = error # "value" contextual keyword should be used -dotnet_diagnostic.S3427.severity = error # Method overloads with default parameter values should not overlap -dotnet_diagnostic.S3433.severity = error # Test method signatures should be correct -dotnet_diagnostic.S3443.severity = error # Type should not be examined on "System.Type" instances -dotnet_diagnostic.S3875.severity = error # "operator==" should not be overloaded on reference types -dotnet_diagnostic.S3877.severity = error # Exceptions should not be thrown from unexpected methods -dotnet_diagnostic.S4462.severity = error # Calls to "async" methods should not be blocking -dotnet_diagnostic.S6422.severity = error # Calls to "async" methods should not be blocking in Azure Functions -dotnet_diagnostic.S6424.severity = error # Interfaces for durable entities should satisfy the restrictions - -################### -# SonarAnalyzer (Sxxxx) - Critical Code Smell -################### -dotnet_diagnostic.S1006.severity = error # Method overrides should not change parameter defaults +dotnet_diagnostic.S2387.severity = none # Child class fields should not shadow parent class fields — covered by SST1484 +dotnet_diagnostic.S2437.severity = none # Unnecessary bit operations should not be performed — covered by SST1481 +dotnet_diagnostic.S2699.severity = none # Tests should include assertions -> replaced by SST2500 +dotnet_diagnostic.S2953.severity = none # Methods named "Dispose" should implement "IDisposable.Dispose" — covered by SST2316 +dotnet_diagnostic.S2970.severity = none # Assertions should be complete -> replaced by SST2508 +dotnet_diagnostic.S3060.severity = none # "is" should not be used with "this" -> replaced by SST2327 +dotnet_diagnostic.S3237.severity = none # "value" contextual keyword should be used — covered by SST2429 +dotnet_diagnostic.S3427.severity = none # Method overloads with default parameter values should not overlap — covered by SST2319 +dotnet_diagnostic.S3433.severity = none # Test method signatures should be correct -> replaced by SST2509 +dotnet_diagnostic.S3443.severity = none # Type should not be examined on "System.Type" instances — covered by SST2432 +dotnet_diagnostic.S3875.severity = none # "operator==" should not be overloaded on reference types -> replaced by SST2464 +dotnet_diagnostic.S3877.severity = none # Exceptions should not be thrown from unexpected methods — covered by SST1485 +dotnet_diagnostic.S4462.severity = none # Calls to "async" methods should not be blocking - covered by PSH1315 +dotnet_diagnostic.S6422.severity = none # Calls to "async" methods should not be blocking in Azure Functions — covered by PSH1315 +dotnet_diagnostic.S6424.severity = none # Interfaces for durable entities should satisfy the restrictions -> off: Durable Entity-specific; not used in this library + +# Critical code smells +dotnet_diagnostic.S1006.severity = none # Method overrides should not change parameter defaults — covered by SST2424 dotnet_diagnostic.S1067.severity = none # Expressions should not be too complex -dotnet_diagnostic.S1163.severity = error # Exceptions should not be thrown in finally blocks -dotnet_diagnostic.S1186.severity = error # Methods should not be empty -dotnet_diagnostic.S121.severity = error # Control structures should use curly braces (kept over SA1503 — Sonar 20ms vs SA1503 50ms) -dotnet_diagnostic.S1215.severity = none # "GC.Collect" should not be called +dotnet_diagnostic.S1163.severity = none # Exceptions should not be thrown in finally blocks -> replaced by CA2219 +dotnet_diagnostic.S1186.severity = none # Methods should not be empty — covered by SST1438 +dotnet_diagnostic.S121.severity = none # Control structures should use curly braces (kept over SA1503 — Sonar 20ms vs SA1503 50ms) -> replaced by SST1503 +dotnet_diagnostic.S1215.severity = none # "GC.Collect" should not be called — covered by PSH1021 dotnet_diagnostic.S126.severity = none # "if ... else if" constructs should end with "else" clauses dotnet_diagnostic.S131.severity = none # "switch/Select" statements should contain a "default/Case Else" clauses dotnet_diagnostic.S134.severity = none # Control flow statements "if", "switch", "for", "foreach", "while", "do" and "try" should not be nested too deeply -dotnet_diagnostic.S1541.severity = error # Methods and properties should not be too complex -dotnet_diagnostic.S1699.severity = error # Constructors should only call non-overridable methods -dotnet_diagnostic.S1821.severity = error # "switch" statements should not be nested -dotnet_diagnostic.S1944.severity = error # Invalid casts should be avoided -dotnet_diagnostic.S1994.severity = error # "for" loop increment clauses should modify the loops' counters -dotnet_diagnostic.S2197.severity = error # Modulus results should not be checked for direct equality -dotnet_diagnostic.S2198.severity = error # Unnecessary mathematical comparisons should not be made +dotnet_diagnostic.S1541.severity = none # Methods and properties should not be too complex - covered by SST1442 +dotnet_diagnostic.S1699.severity = none # Constructors should only call non-overridable methods — covered by SST1483 +dotnet_diagnostic.S1821.severity = none # "switch" statements should not be nested -> replaced by SST2252 +dotnet_diagnostic.S1944.severity = none # Invalid casts should be avoided -> replaced by compiler CS0030 +dotnet_diagnostic.S1994.severity = none # "for" loop increment clauses should modify the loops' counters — covered by SST2411 +dotnet_diagnostic.S2197.severity = none # Modulus results should not be checked for direct equality — covered by SST2416 +dotnet_diagnostic.S2198.severity = none # Unnecessary mathematical comparisons should not be made -> replaced by SST2489 dotnet_diagnostic.S2223.severity = none # Non-constant static fields should not be visible - DUPLICATE CA2211 -dotnet_diagnostic.S2290.severity = error # Field-like events should not be virtual -dotnet_diagnostic.S2291.severity = error # Overflow checking should not be disabled for "Enumerable.Sum" -dotnet_diagnostic.S2302.severity = error # "nameof" should be used -dotnet_diagnostic.S2330.severity = error # Array covariance should not be used -dotnet_diagnostic.S2339.severity = error # Public constant members should not be used +dotnet_diagnostic.S2290.severity = none # Field-like events should not be virtual -> replaced by SST2456 +dotnet_diagnostic.S2291.severity = none # Overflow checking should not be disabled for "Enumerable.Sum" — covered by SST2457 +dotnet_diagnostic.S2302.severity = none # "nameof" should be used — covered by SST1415 +dotnet_diagnostic.S2330.severity = none # Array covariance should not be used — covered by SST2434 +dotnet_diagnostic.S2339.severity = none # Public constant members should not be used — covered by SST2311 dotnet_diagnostic.S2346.severity = none # Flags enumerations zero-value members should be named "None" - DUPLICATE CA1008 -dotnet_diagnostic.S2360.severity = error # Optional parameters should not be used -dotnet_diagnostic.S2365.severity = error # Properties should not make collection or array copies -dotnet_diagnostic.S2479.severity = error # Whitespace and control characters in string literals should be explicit -dotnet_diagnostic.S2692.severity = error # "IndexOf" checks should not be for positive numbers -dotnet_diagnostic.S2696.severity = error # Instance members should not write to "static" fields -dotnet_diagnostic.S2701.severity = error # Literal boolean values should not be used in assertions -dotnet_diagnostic.S3215.severity = error # "interface" instances should not be cast to concrete types -dotnet_diagnostic.S3216.severity = error # "ConfigureAwait(false)" should be used -dotnet_diagnostic.S3217.severity = error # "Explicit" conversions of "foreach" loops should not be used -dotnet_diagnostic.S3218.severity = error # Inner class members should not shadow outer class "static" or type members -dotnet_diagnostic.S3265.severity = error # Non-flags enums should not be used in bitwise operations -dotnet_diagnostic.S3353.severity = error # Unchanged variables should be marked as "const" -dotnet_diagnostic.S3447.severity = error # "[Optional]" should not be used on "ref" or "out" parameters -dotnet_diagnostic.S3451.severity = error # "[DefaultValue]" should not be used when "[DefaultParameterValue]" is meant -dotnet_diagnostic.S3600.severity = error # "params" should not be introduced on overrides -dotnet_diagnostic.S3776.severity = error # Cognitive Complexity of methods should not be too high -dotnet_diagnostic.S3871.severity = error # Exception types should be "public" +dotnet_diagnostic.S2360.severity = none # Optional parameters should not be used — conflicts with SST2433, which owns caller-info parameters requiring a default +dotnet_diagnostic.S2365.severity = none # Properties should not make collection or array copies — covered by PSH1017 +dotnet_diagnostic.S2479.severity = none # Whitespace and control characters in string literals should be explicit — covered by SST1192 +dotnet_diagnostic.S2692.severity = none # "IndexOf" checks should not be for positive numbers — covered by SST2420 +dotnet_diagnostic.S2696.severity = none # Instance members should not write to "static" fields -> replaced by SST2402 +dotnet_diagnostic.S2701.severity = none # Literal boolean values should not be used in assertions — covered by SST2503 +dotnet_diagnostic.S3215.severity = none # "interface" instances should not be cast to concrete types -> deliberately unenforced, same reason as SST2326 +dotnet_diagnostic.S3216.severity = none # "ConfigureAwait(false)" should be used -> replaced by CA2007 +dotnet_diagnostic.S3217.severity = none # "Explicit" conversions of "foreach" loops should not be used — covered by SST2225 +dotnet_diagnostic.S3218.severity = none # Inner class members should not shadow outer class "static" or type members — covered by SST1484 +dotnet_diagnostic.S3265.severity = none # Non-flags enums should not be used in bitwise operations — covered by SST2458 +dotnet_diagnostic.S3353.severity = none # Unchanged variables should be marked as "const" — covered by PSH1402 +dotnet_diagnostic.S3447.severity = none # "[Optional]" should not be used on "ref" or "out" parameters — covered by SST2459 +dotnet_diagnostic.S3451.severity = none # "[DefaultValue]" should not be used when "[DefaultParameterValue]" is meant — covered by SST2460 +dotnet_diagnostic.S3600.severity = none # "params" should not be introduced on overrides — covered by SST2426 +dotnet_diagnostic.S3776.severity = none # Cognitive Complexity of methods should not be too high - covered by SST1443 +dotnet_diagnostic.S3871.severity = none # Exception types should be "public" -> replaced by CA1064 dotnet_diagnostic.S3874.severity = none # "out" and "ref" parameters — repo idiom is TryX(..., out T value) -dotnet_diagnostic.S3904.severity = error # Assemblies should have version information -dotnet_diagnostic.S3937.severity = error # Number patterns should be regular -dotnet_diagnostic.S3972.severity = error # Conditionals should start on new lines -dotnet_diagnostic.S3973.severity = error # A conditionally executed single line should be denoted by indentation -dotnet_diagnostic.S3998.severity = error # Threads should not lock on objects with weak identity -dotnet_diagnostic.S4000.severity = error # Pointers to unmanaged memory should not be visible -dotnet_diagnostic.S4015.severity = error # Inherited member visibility should not be decreased -dotnet_diagnostic.S4019.severity = error # Base class methods should not be hidden -dotnet_diagnostic.S4025.severity = error # Child class fields should not differ from parent class fields only by capitalization +dotnet_diagnostic.S3904.severity = none # Assemblies should have version information -> replaced by obsolete (SDK supplies assembly version) +dotnet_diagnostic.S3937.severity = none # Number patterns should be regular — covered by SST1119 +dotnet_diagnostic.S3972.severity = none # Conditionals should start on new lines — covered by SST1146 +dotnet_diagnostic.S3973.severity = none # A conditionally executed single line should be denoted by indentation -> replaced by SST1503 +dotnet_diagnostic.S3998.severity = none # Threads should not lock on objects with weak identity -> replaced by SST1902 +dotnet_diagnostic.S4000.severity = none # Pointers to unmanaged memory should not be visible -> replaced by SST2328 +dotnet_diagnostic.S4015.severity = none # Inherited member visibility should not be decreased — covered by SST2462 +dotnet_diagnostic.S4019.severity = none # Base class methods should not be hidden — covered by SST2427 +dotnet_diagnostic.S4025.severity = none # Child class fields should not differ from parent class fields only by capitalization — covered by SST2463 dotnet_diagnostic.S4039.severity = none # Interface methods should be callable by derived types - DUPLICATE CA1033 dotnet_diagnostic.S4487.severity = none # Unread "private" fields should be removed -dotnet_diagnostic.S4524.severity = error # "default" clauses should be first or last -dotnet_diagnostic.S4635.severity = error # Start index should be used instead of calling Substring -dotnet_diagnostic.S5034.severity = error # "ValueTask" should be consumed correctly -dotnet_diagnostic.S6967.severity = error # ModelState.IsValid should be called in controller actions -dotnet_diagnostic.S8367.severity = error # Identifiers should not conflict with the C# 14 "field" contextual keyword -dotnet_diagnostic.S8368.severity = error # Identifiers should not conflict with the C# 14 "extension" contextual keyword -dotnet_diagnostic.S8380.severity = error # Return types named "partial" should be escaped with "@" -dotnet_diagnostic.S8381.severity = error # "scoped" should be escaped when used as an identifier or type name in parenthesized lambda parameter lists +dotnet_diagnostic.S4524.severity = none # "default" clauses should be first or last — covered by SST1219 +dotnet_diagnostic.S4635.severity = none # Start index should be used instead of calling Substring — covered by PSH1218 +dotnet_diagnostic.S5034.severity = none # "ValueTask" should be consumed correctly — covered by PSH1316 +dotnet_diagnostic.S6967.severity = none # ModelState.IsValid should be called in controller actions -> off: ASP.NET MVC-specific; no controllers in this library +dotnet_diagnostic.S8367.severity = none # Identifiers should not conflict with the C# 14 "field" contextual keyword - the C# 14 compiler reports this: CS9273 (error) for a local named field in an accessor, CS9258 (warning) for a rebinding read +dotnet_diagnostic.S8368.severity = none # Identifiers should not conflict with the C# 14 "extension" contextual keyword - the C# 14 compiler reports this as CS9306, and SST1300 already flags the lowercase type name +dotnet_diagnostic.S8380.severity = none # Return types named "partial" should be escaped with "@" - the compiler reports this as CS8981, and SST1300 already flags the lowercase type name +dotnet_diagnostic.S8381.severity = none # "scoped" should be escaped when used as an identifier or type name in parenthesized lambda parameter lists -> replaced by compiler dotnet_diagnostic.S927.severity = none # Parameter names should match base declaration and other partial definitions - DUPLICATE CA1725 -################### -# SonarAnalyzer (Sxxxx) - Major Code Smell -################### -dotnet_diagnostic.S103.severity = error # Lines should not be too long -dotnet_diagnostic.S104.severity = error # Files should not have too many lines of code -dotnet_diagnostic.S106.severity = error # Standard outputs should not be used directly to log anything -dotnet_diagnostic.S1066.severity = error # Mergeable "if" statements should be combined -dotnet_diagnostic.S107.severity = error # Methods should not have too many parameters -dotnet_diagnostic.S108.severity = error # Nested blocks of code should not be left empty -dotnet_diagnostic.S109.severity = error # Magic numbers should not be used -dotnet_diagnostic.S110.severity = error # Inheritance tree of classes should not be too deep -dotnet_diagnostic.S1110.severity = error # Redundant pairs of parentheses should be removed -dotnet_diagnostic.S1117.severity = error # Local variables should not shadow class fields or properties +# Major code smells +dotnet_diagnostic.S103.severity = none # Lines should not be too long — covered by SST1521 +dotnet_diagnostic.S104.severity = none # Files should not have too many lines of code — covered by SST1522 +dotnet_diagnostic.S106.severity = none # Covered by SST1449 (canonical) +dotnet_diagnostic.S1066.severity = none # Mergeable "if" statements should be combined — covered by SST2013 +dotnet_diagnostic.S107.severity = none # Methods should not have too many parameters — covered by SST1472 +dotnet_diagnostic.S108.severity = none # Nested blocks of code should not be left empty — covered by SST1439 +dotnet_diagnostic.S109.severity = none # Magic numbers should not be used — covered by SST1471 +dotnet_diagnostic.S110.severity = none # Inheritance tree of classes should not be too deep — covered by SST1446 +dotnet_diagnostic.S1110.severity = none # Redundant pairs of parentheses should be removed — covered by SST1459 +dotnet_diagnostic.S1117.severity = none # Local variables should not shadow class fields or properties — covered by SST1484 dotnet_diagnostic.S1118.severity = none # Utility classes should not have public constructors - DUPLICATE CA1052 -dotnet_diagnostic.S112.severity = error # General or reserved exceptions should never be thrown -dotnet_diagnostic.S1121.severity = error # Assignments should not be made from within sub-expressions -dotnet_diagnostic.S1123.severity = error # "Obsolete" attributes should include explanations -dotnet_diagnostic.S1134.severity = error # Track uses of "FIXME" tags -dotnet_diagnostic.S1144.severity = none # Unused private types or members should be removed - DUPLICATE IDE0051 -dotnet_diagnostic.S1151.severity = error # "switch case" clauses should not have too many lines of code -dotnet_diagnostic.S1168.severity = error # Empty arrays and collections should be returned instead of null -dotnet_diagnostic.S1172.severity = error # Unused method parameters should be removed +dotnet_diagnostic.S112.severity = none # General or reserved exceptions should never be thrown — covered by SST2409 +dotnet_diagnostic.S1121.severity = none # Assignments should not be made from within sub-expressions — covered by SST1187 +dotnet_diagnostic.S1123.severity = none # "Obsolete" attributes should include explanations — covered by SST2308 +dotnet_diagnostic.S1134.severity = none # Track uses of "FIXME" tags -> off: TODO comment tracker; not enforced here +dotnet_diagnostic.S1144.severity = none # Covered by SST1440 (canonical) +dotnet_diagnostic.S1151.severity = none # "switch case" clauses should not have too many lines of code — covered by SST1524 +dotnet_diagnostic.S1168.severity = none # Empty arrays and collections should be returned instead of null — covered by SST2306 +dotnet_diagnostic.S1172.severity = none # Unused method parameters should be removed — covered by SST1461 dotnet_diagnostic.S1200.severity = none # Classes should not be coupled to too many other classes -dotnet_diagnostic.S122.severity = error # Statements should be on separate lines -dotnet_diagnostic.S125.severity = error # Sections of code should not be commented out -dotnet_diagnostic.S127.severity = error # "for" loop stop conditions should be invariant -dotnet_diagnostic.S138.severity = error # Functions should not have too many lines of code -dotnet_diagnostic.S1479.severity = error # "switch" statements with many "case" clauses should have only one statement -dotnet_diagnostic.S1607.severity = error # Tests should not be ignored -dotnet_diagnostic.S1696.severity = error # NullReferenceException should not be caught +dotnet_diagnostic.S122.severity = none # Statements should be on separate lines — covered by SST1107 +dotnet_diagnostic.S125.severity = none # Sections of code should not be commented out — covered by SST1148 +dotnet_diagnostic.S127.severity = none # "for" loop stop conditions should be invariant — covered by SST2465 +dotnet_diagnostic.S138.severity = none # Functions should not have too many lines of code — covered by SST1523 +dotnet_diagnostic.S1479.severity = none # "switch" statements with many "case" clauses — covered by SST1423 +dotnet_diagnostic.S1607.severity = none # Tests should not be ignored -> off: ignored-test tracker; not enforced here +dotnet_diagnostic.S1696.severity = none # NullReferenceException should not be caught — covered by SST2401 dotnet_diagnostic.S1854.severity = none # Unused assignments should be removed - DUPLICATE IDE0059 -dotnet_diagnostic.S1871.severity = error # Two branches in a conditional structure should not have exactly the same implementation -dotnet_diagnostic.S2139.severity = error # Exceptions should be either logged or rethrown but not both +dotnet_diagnostic.S1871.severity = none # Two branches in a conditional structure should not have exactly the same implementation — covered by SST2414 +dotnet_diagnostic.S2139.severity = none # Exceptions should be either logged or rethrown but not both -> replaced by SST2488 dotnet_diagnostic.S2166.severity = none # Classes named like "Exception" should extend "Exception" or a subclass - DUPLICATE CA1710 -dotnet_diagnostic.S2234.severity = error # Arguments should be passed in the same order as the method parameters -dotnet_diagnostic.S2326.severity = error # Unused type parameters should be removed -dotnet_diagnostic.S2327.severity = error # "try" statements with identical "catch" and/or "finally" blocks should be merged -dotnet_diagnostic.S2357.severity = error # Fields should be private -dotnet_diagnostic.S2372.severity = error # Exceptions should not be thrown from property getters -dotnet_diagnostic.S2376.severity = error # Write-only properties should not be used -dotnet_diagnostic.S2629.severity = error # Logging templates should be constant -dotnet_diagnostic.S2681.severity = error # Multiline blocks should be enclosed in curly braces -dotnet_diagnostic.S2743.severity = none # Static fields should not be used in generic types - DUPLICATE CA1000 -dotnet_diagnostic.S2925.severity = error # "Thread.Sleep" should not be used in tests +dotnet_diagnostic.S2234.severity = none # Arguments should be passed in the same order as the method parameters -> replaced by SST2400 +dotnet_diagnostic.S2326.severity = none # Covered by SST1452 (canonical) +dotnet_diagnostic.S2327.severity = none # "try" statements with identical "catch" and/or "finally" blocks should be merged -> replaced by SST2490 +dotnet_diagnostic.S2357.severity = none # Fields should be private — duplicate of SST1401 (canonical); fields intentionally exposed (e.g. public test fields for reflection) already carry per-site SST1401 suppressions +dotnet_diagnostic.S2372.severity = none # Exceptions should not be thrown from property getters — covered by SST1485 +dotnet_diagnostic.S2376.severity = none # Write-only properties should not be used — covered by SST1421 +dotnet_diagnostic.S2629.severity = none # Logging templates should be constant -> replaced by CA2254 +dotnet_diagnostic.S2681.severity = none # Multiline blocks should be enclosed in curly braces — covered by SST1503 +dotnet_diagnostic.S2743.severity = none # Static fields should not be used in generic types - DUPLICATE CA1000 — covered by SST1431 +dotnet_diagnostic.S2925.severity = none # "Thread.Sleep" should not be used in tests — covered by SST2506 dotnet_diagnostic.S2933.severity = none # Fields that are only assigned in the constructor should be "readonly" - DUPLICATE IDE0044 -dotnet_diagnostic.S2971.severity = error # LINQ expressions should be simplified -dotnet_diagnostic.S3010.severity = error # Static fields should not be updated in constructors -dotnet_diagnostic.S3011.severity = error # Reflection should not be used to increase accessibility of classes, methods, or fields +dotnet_diagnostic.S2971.severity = none # LINQ expressions should be simplified — covered by PSH1101/PSH1102 +dotnet_diagnostic.S3010.severity = none # Static fields should not be updated in constructors — covered by SST2402 +dotnet_diagnostic.S3011.severity = none # Reflection should not be used to increase accessibility of classes, methods, or fields -> replaced by SES1406 dotnet_diagnostic.S3059.severity = none # Types should not have members with visibility set higher than the type's visibility -dotnet_diagnostic.S3063.severity = error # "StringBuilder" data should be used -dotnet_diagnostic.S3169.severity = error # Multiple "OrderBy" calls should not be used -dotnet_diagnostic.S3246.severity = error # Generic type parameters should be co/contravariant when possible -dotnet_diagnostic.S3262.severity = error # "params" should be used on overrides -dotnet_diagnostic.S3264.severity = error # Events should be invoked -dotnet_diagnostic.S3358.severity = error # Ternary operators should not be nested -dotnet_diagnostic.S3366.severity = error # "this" should not be exposed from constructors -dotnet_diagnostic.S3415.severity = error # Assertion arguments should be passed in the correct order -dotnet_diagnostic.S3431.severity = error # "[ExpectedException]" should not be used -dotnet_diagnostic.S3442.severity = error # "abstract" classes should not have "public" constructors -dotnet_diagnostic.S3445.severity = error # Exceptions should not be explicitly rethrown -dotnet_diagnostic.S3457.severity = error # Composite format strings should be used correctly -dotnet_diagnostic.S3597.severity = error # "ServiceContract" and "OperationContract" attributes should be used together -dotnet_diagnostic.S3880.severity = error # Finalizers should not be empty -dotnet_diagnostic.S3881.severity = error # "IDisposable" should be implemented correctly -dotnet_diagnostic.S3885.severity = error # "Assembly.Load" should be used -dotnet_diagnostic.S3898.severity = error # Value types should implement "IEquatable" -dotnet_diagnostic.S3902.severity = error # "Assembly.GetExecutingAssembly" should not be called -dotnet_diagnostic.S3906.severity = error # Event Handlers should have the correct signature -dotnet_diagnostic.S3908.severity = error # Generic event handlers should be used -dotnet_diagnostic.S3909.severity = error # Collections should implement the generic interface +dotnet_diagnostic.S3063.severity = none # "StringBuilder" data should be used — covered by SST2408 +dotnet_diagnostic.S3169.severity = none # Multiple "OrderBy" calls should not be used — covered by PSH1108 +dotnet_diagnostic.S3246.severity = none # Generic type parameters should be co/contravariant when possible -> off: low-precision variance suggestion; not enforced +dotnet_diagnostic.S3262.severity = none # "params" should be used on overrides — covered by SST2426 +dotnet_diagnostic.S3264.severity = none # Events should be invoked — covered by SST2407 +dotnet_diagnostic.S3358.severity = none # Ternary operators should not be nested — covered by SST1147 +dotnet_diagnostic.S3366.severity = none # "this" should not be exposed from constructors — covered by SST2403 +dotnet_diagnostic.S3415.severity = none # Assertion arguments should be passed in the correct order — covered by SST2502 +dotnet_diagnostic.S3431.severity = none # "[ExpectedException]" should not be used — covered by SST2507 +dotnet_diagnostic.S3442.severity = none # "abstract" classes should not have "public" constructors — covered by SST1428 +dotnet_diagnostic.S3445.severity = none # Exceptions should not be explicitly rethrown — covered by SST1430 +dotnet_diagnostic.S3457.severity = none # Composite format strings should be used correctly — covered by SST1454 +dotnet_diagnostic.S3597.severity = none # "ServiceContract" and "OperationContract" attributes should be used together -> replaced by obsolete (WCF) +dotnet_diagnostic.S3880.severity = none # Finalizers should not be empty — covered by PSH1002 +dotnet_diagnostic.S3881.severity = none # "IDisposable" should be implemented correctly — covered by SST2300 +dotnet_diagnostic.S3885.severity = none # "Assembly.Load" should be used -> replaced by SST2486 +dotnet_diagnostic.S3898.severity = none # Covered by PSH1005 (canonical) +dotnet_diagnostic.S3902.severity = none # Covered by PSH1404 (canonical) +dotnet_diagnostic.S3906.severity = none # Event Handlers should have the correct signature — covered by SST2304 +dotnet_diagnostic.S3908.severity = none # Generic event handlers should be used -> replaced by SST2304 +dotnet_diagnostic.S3909.severity = none # Collections should implement the generic interface -> replaced by CA1010 dotnet_diagnostic.S3925.severity = none # "ISerializable" should be implemented correctly - BinaryFormatter / ISerializable serialization is obsoleted (SYSLIB0050/0051) in modern .NET; we do not opt into legacy serialization for any exception type dotnet_diagnostic.S3928.severity = none # Parameter names used into ArgumentException constructors should match an existing one - DUPLICATE CA2208 dotnet_diagnostic.S3956.severity = none # "Generic.List" instances should not be part of public APIs -dotnet_diagnostic.S3971.severity = error # "GC.SuppressFinalize" should not be called -dotnet_diagnostic.S3990.severity = error # Assemblies should be marked as CLS compliant -dotnet_diagnostic.S3992.severity = error # Assemblies should explicitly specify COM visibility -dotnet_diagnostic.S3993.severity = error # Custom attributes should be marked with "System.AttributeUsageAttribute" +dotnet_diagnostic.S3971.severity = none # "GC.SuppressFinalize" should not be called — conflicts with PSH1008, which owns the pointless-SuppressFinalize direction and exempts unsealed types +dotnet_diagnostic.S3990.severity = none # Assemblies should be marked as CLS compliant -> replaced by CA1014 +dotnet_diagnostic.S3992.severity = none # Assemblies should explicitly specify COM visibility -> replaced by CA1017 +dotnet_diagnostic.S3993.severity = none # Custom attributes should be marked with "System.AttributeUsageAttribute" -> replaced by CA1018 dotnet_diagnostic.S3994.severity = none # URI Parameters should not be strings dotnet_diagnostic.S3995.severity = none # URI return values should not be strings dotnet_diagnostic.S3996.severity = none # URI properties should not be strings -dotnet_diagnostic.S3997.severity = error # String URI overloads should call "System.Uri" overloads -dotnet_diagnostic.S4002.severity = error # Disposable types should declare finalizers -dotnet_diagnostic.S4004.severity = error # Collection properties should be readonly +dotnet_diagnostic.S3997.severity = none # String URI overloads should call "System.Uri" overloads -> replaced by CA1054/CA1056/CA1057 +dotnet_diagnostic.S4002.severity = none # Disposable types should declare finalizers — covered by SST2317 +dotnet_diagnostic.S4004.severity = none # Collection properties should be readonly — covered by SST2305 dotnet_diagnostic.S4005.severity = none # "System.Uri" arguments should be used instead of strings -dotnet_diagnostic.S4016.severity = error # Enumeration members should not be named "Reserved" +dotnet_diagnostic.S4016.severity = none # Enumeration members should not be named "Reserved" -> replaced by CA1700 dotnet_diagnostic.S4017.severity = none # Method signatures should not contain nested generic types -dotnet_diagnostic.S4035.severity = error # Classes implementing "IEquatable" should be sealed -dotnet_diagnostic.S4050.severity = error # Operators should be overloaded consistently +dotnet_diagnostic.S4035.severity = none # Classes implementing "IEquatable" should be sealed — covered by SST2301 +dotnet_diagnostic.S4050.severity = none # Operators should be overloaded consistently — covered by SST2302 dotnet_diagnostic.S4055.severity = none # Literals should not be passed as localized parameters -dotnet_diagnostic.S4057.severity = error # Locales should be set for data types +dotnet_diagnostic.S4057.severity = none # Locales should be set for data types -> replaced by obsolete dotnet_diagnostic.S4059.severity = none # Property names should not match get methods - DUPLICATE CA1721 -dotnet_diagnostic.S4070.severity = error # Non-flags enums should not be marked with "FlagsAttribute" -dotnet_diagnostic.S4144.severity = error # Methods should not have identical implementations -dotnet_diagnostic.S4200.severity = error # Native methods should be wrapped +dotnet_diagnostic.S4070.severity = none # Non-flags enums should not be marked with "FlagsAttribute" — covered by SST2303 +dotnet_diagnostic.S4144.severity = none # Methods should not have identical implementations — covered by SST2318 +dotnet_diagnostic.S4200.severity = none # Native methods should be wrapped -> replaced by CA1401 dotnet_diagnostic.S4214.severity = none # "P/Invoke" methods should not be visible - DUPLICATE CA1401 -dotnet_diagnostic.S4220.severity = error # Events should have proper arguments -dotnet_diagnostic.S4456.severity = error # Parameter validation in yielding methods should be wrapped -dotnet_diagnostic.S4457.severity = none # Parameter validation in "async"/"await" methods should be wrapped -dotnet_diagnostic.S4545.severity = error # "DebuggerDisplayAttribute" strings should reference existing members -dotnet_diagnostic.S4581.severity = error # "new Guid()" should not be used -dotnet_diagnostic.S6354.severity = error # Use a testable date/time provider -dotnet_diagnostic.S6419.severity = error # Azure Functions should be stateless -dotnet_diagnostic.S6420.severity = error # Client instances should not be recreated on each Azure Function invocation -dotnet_diagnostic.S6421.severity = error # Azure Functions should use Structured Error Handling -dotnet_diagnostic.S6423.severity = error # Azure Functions should log all failures -dotnet_diagnostic.S6561.severity = error # Avoid using "DateTime.Now" for benchmarking or timing operations -dotnet_diagnostic.S6562.severity = error # Always set the "DateTimeKind" when creating new "DateTime" instances -dotnet_diagnostic.S6563.severity = error # Use UTC when recording DateTime instants -dotnet_diagnostic.S6566.severity = error # Use "DateTimeOffset" instead of "DateTime" -dotnet_diagnostic.S6575.severity = error # Use "TimeZoneInfo.FindSystemTimeZoneById" without converting the timezones with "TimezoneConverter" +dotnet_diagnostic.S4220.severity = none # Events should have proper arguments — covered by SST2436 +dotnet_diagnostic.S4456.severity = none # Parameter validation in yielding methods should be wrapped — covered by SST2404 +dotnet_diagnostic.S4457.severity = none # Parameter validation in "async"/"await" methods should be wrapped — covered by SST2325 +dotnet_diagnostic.S4545.severity = none # "DebuggerDisplayAttribute" strings should reference existing members — covered by SST2405 +dotnet_diagnostic.S4581.severity = none # "new Guid()" should not be used — covered by SST2012 +dotnet_diagnostic.S6354.severity = none # Use a testable date/time provider — covered by SST2010 +dotnet_diagnostic.S6419.severity = none # Azure Functions should be stateless -> off: Azure Functions-specific; not used in this library +dotnet_diagnostic.S6420.severity = none # Client instances should not be recreated on each Azure Function invocation — covered by PSH1418 +dotnet_diagnostic.S6421.severity = none # Azure Functions should use Structured Error Handling -> off: Azure Functions-specific; not used in this library +dotnet_diagnostic.S6423.severity = none # Azure Functions should log all failures -> off: Azure Functions-specific; not used in this library +dotnet_diagnostic.S6561.severity = none # Avoid using "DateTime.Now" for benchmarking or timing operations — covered by PSH1408 +dotnet_diagnostic.S6562.severity = none # Covered by SST1451 (canonical) +dotnet_diagnostic.S6563.severity = none # Use UTC when recording DateTime instants — covered by SST2011 +dotnet_diagnostic.S6566.severity = none # Use "DateTimeOffset" instead of "DateTime" — covered by SST2016 +dotnet_diagnostic.S6575.severity = none # Use "TimeZoneInfo.FindSystemTimeZoneById" without converting the timezones with "TimezoneConverter" -> replaced by PSH1419 dotnet_diagnostic.S6580.severity = none # Use a format provider when parsing date and time - DUPLICATE CA1305 -dotnet_diagnostic.S6673.severity = error # Log message template placeholders should be in the right order -dotnet_diagnostic.S6802.severity = error # Using lambda expressions in loops should be avoided in Blazor markup section -dotnet_diagnostic.S6803.severity = error # Parameters with SupplyParameterFromQuery attribute should be used only in routable components -dotnet_diagnostic.S6931.severity = error # ASP.NET controller actions should not have a route template starting with "/" -dotnet_diagnostic.S6932.severity = error # Use model binding instead of reading raw request data -dotnet_diagnostic.S6934.severity = error # A Route attribute should be added to the controller when a route template is specified at the action level -dotnet_diagnostic.S6960.severity = error # Controllers should not have mixed responsibilities -dotnet_diagnostic.S6961.severity = error # API Controllers should derive from ControllerBase instead of Controller -dotnet_diagnostic.S6962.severity = error # You should pool HTTP connections with HttpClientFactory -dotnet_diagnostic.S6964.severity = error # Value type property used as input in a controller action should be nullable, required or annotated with the JsonRequiredAttribute to avoid under-posting. -dotnet_diagnostic.S6965.severity = error # REST API actions should be annotated with an HTTP verb attribute -dotnet_diagnostic.S6966.severity = error # Awaitable method should be used -dotnet_diagnostic.S6968.severity = error # Actions that return a value should be annotated with ProducesResponseTypeAttribute containing the return type -dotnet_diagnostic.S881.severity = error # Increment (++) and decrement (--) operators should not be used in a method call or mixed with other operators in an expression -dotnet_diagnostic.S907.severity = error # "goto" statement should not be used - -################### -# SonarAnalyzer (Sxxxx) - Minor Code Smell -################### -dotnet_diagnostic.S100.severity = error # Methods and properties should be named in PascalCase (kept over SA1300 — S100+S101 47ms vs SA1300 101ms) -dotnet_diagnostic.S101.severity = error # Types should be named in PascalCase (kept over SA1300 — see S100) -dotnet_diagnostic.S105.severity = error # Tabulation characters should not be used +dotnet_diagnostic.S6673.severity = none # Log message template placeholders should be in the right order — covered by SST2440 +dotnet_diagnostic.S6802.severity = none # Using lambda expressions in loops should be avoided in Blazor markup section -> replaced by PSH1600 +dotnet_diagnostic.S6803.severity = none # Parameters with SupplyParameterFromQuery attribute should be used only in routable components -> off: Blazor-specific; no Blazor surface in this library +dotnet_diagnostic.S6931.severity = none # ASP.NET controller actions should not have a route template starting with "/" -> off: ASP.NET MVC-specific; no controllers in this library +dotnet_diagnostic.S6932.severity = none # Use model binding instead of reading raw request data -> off: ASP.NET MVC-specific; no controllers in this library +dotnet_diagnostic.S6934.severity = none # A Route attribute should be added to the controller when a route template is specified at the action level -> off: ASP.NET MVC-specific; no controllers in this library +dotnet_diagnostic.S6960.severity = none # Controllers should not have mixed responsibilities -> off: ASP.NET MVC-specific; no controllers in this library +dotnet_diagnostic.S6961.severity = none # API Controllers should derive from ControllerBase instead of Controller -> off: ASP.NET MVC-specific; no controllers in this library +dotnet_diagnostic.S6962.severity = none # You should pool HTTP connections with HttpClientFactory — covered by PSH1418 +dotnet_diagnostic.S6964.severity = none # Value type property used as input in a controller action should be nullable, required or annotated with the JsonRequiredAttribute to avoid under-posting. -> replaced by SST2705 (opt-in) +dotnet_diagnostic.S6965.severity = none # REST API actions should be annotated with an HTTP verb attribute -> replaced by SST2704 +dotnet_diagnostic.S6966.severity = none # Awaitable method should be used — covered by PSH1313 +dotnet_diagnostic.S6968.severity = none # Actions that return a value should be annotated with ProducesResponseTypeAttribute containing the return type -> off: ASP.NET MVC-specific; no controllers in this library +dotnet_diagnostic.S881.severity = none # Increment (++) and decrement (--) operators should not be used in a method call or mixed with other operators in an expression — covered by SST2015 +dotnet_diagnostic.S907.severity = none # "goto" statement should not be used — covered by SST2014 + +# Minor code smells +dotnet_diagnostic.S100.severity = none # Methods and properties should be named in PascalCase — covered by SST1300 +dotnet_diagnostic.S101.severity = none # Types should be named in PascalCase — covered by SST1300 +dotnet_diagnostic.S105.severity = none # Tabulation characters should not be used — covered by SST1027 dotnet_diagnostic.S1104.severity = none # Fields should not have public accessibility - DUPLICATE CA1051 -dotnet_diagnostic.S1109.severity = error # A close curly brace should be located at the beginning of a line +dotnet_diagnostic.S1109.severity = none # A close curly brace should be located at the beginning of a line — covered by SST1500 dotnet_diagnostic.S1116.severity = none # Empty statements should be removed - DUPLICATE SA1106 -dotnet_diagnostic.S1125.severity = error # Boolean literals should not be redundant -dotnet_diagnostic.S1128.severity = error # Unnecessary "using" should be removed (kept over IDE0005 — Sonar 551ms vs IDE0005 2.364s) +dotnet_diagnostic.S1125.severity = none # Boolean literals should not be redundant — covered by SST1182 +dotnet_diagnostic.S1128.severity = none # Covered by SST1445 (canonical) dotnet_diagnostic.S113.severity = none # Files should end with a newline -dotnet_diagnostic.S1155.severity = error # "Any()" should be used to test for emptiness +dotnet_diagnostic.S1155.severity = none # "Any()" should be used to test for emptiness — covered by PSH1119 dotnet_diagnostic.S1185.severity = none # Overriding members should do more than simply call the same member in the base class - DUPLICATE RCS1132 -dotnet_diagnostic.S1192.severity = error # String literals should not be duplicated -dotnet_diagnostic.S1199.severity = error # Nested code blocks should not be used +dotnet_diagnostic.S1192.severity = none # String literals should not be duplicated — covered by SST1486 +dotnet_diagnostic.S1199.severity = none # Nested code blocks should not be used — covered by SST1138 dotnet_diagnostic.S1210.severity = none # "Equals" and the comparison operators should be overridden when implementing "IComparable" - DUPLICATE CA1036 dotnet_diagnostic.S1227.severity = none # break statements should not be used except for switch cases -dotnet_diagnostic.S1264.severity = error # A "while" loop should be used instead of a "for" loop +dotnet_diagnostic.S1264.severity = none # A "while" loop should be used instead of a "for" loop — covered by SST2245 dotnet_diagnostic.S1301.severity = none # "switch" statements should have at least 3 "case" clauses dotnet_diagnostic.S1312.severity = none # Logger fields should be "private static readonly" -dotnet_diagnostic.S1449.severity = error # Culture should be specified for "string" operations -dotnet_diagnostic.S1450.severity = error # Private fields only used as local variables in methods should become local variables -dotnet_diagnostic.S1481.severity = error # Unused local variables should be removed -dotnet_diagnostic.S1643.severity = error # Strings should not be concatenated using '+' in a loop -dotnet_diagnostic.S1659.severity = error # Multiple variables should not be declared on the same line -dotnet_diagnostic.S1694.severity = error # An abstract class should have both abstract and concrete methods -dotnet_diagnostic.S1698.severity = error # "==" should not be used when "Equals" is overridden -dotnet_diagnostic.S1858.severity = error # "ToString()" calls should not be redundant -dotnet_diagnostic.S1905.severity = none # Redundant casts should not be used - DUPLICATE IDE0004 -dotnet_diagnostic.S1939.severity = error # Inheritance list should not be redundant -dotnet_diagnostic.S1940.severity = error # Boolean checks should not be inverted -dotnet_diagnostic.S2094.severity = error # Classes should not be empty -dotnet_diagnostic.S2148.severity = error # Underscores should be used to make large numbers readable -dotnet_diagnostic.S2156.severity = error # "sealed" classes should not have "protected" members -dotnet_diagnostic.S2219.severity = error # Runtime type checking should be simplified +dotnet_diagnostic.S1449.severity = none # Culture should be specified for "string" operations — covered by PSH1207 +dotnet_diagnostic.S1450.severity = none # Private fields only used as local variables in methods should become local variables — covered by SST1422 +dotnet_diagnostic.S1481.severity = none # Unused local variables should be removed — covered by SST1497 +dotnet_diagnostic.S1643.severity = none # Covered by PSH1206 (canonical) +dotnet_diagnostic.S1659.severity = none # Multiple variables should not be declared on the same line — covered by SST1132 +dotnet_diagnostic.S1694.severity = none # An abstract class should have both abstract and concrete methods — covered by SST2323 +dotnet_diagnostic.S1698.severity = none # "==" should not be used when "Equals" is overridden — covered by SST1495 +dotnet_diagnostic.S1858.severity = none # "ToString()" calls should not be redundant — covered by PSH1211 +dotnet_diagnostic.S1905.severity = none # Redundant casts should not be used - DUPLICATE IDE0004 — covered by SST1175 +dotnet_diagnostic.S1939.severity = none # Inheritance list should not be redundant — covered by SST1490 and SST1177 +dotnet_diagnostic.S1940.severity = none # Boolean checks should not be inverted — covered by SST1172 +dotnet_diagnostic.S2094.severity = none # Classes should not be empty — covered by SST1436 +dotnet_diagnostic.S2148.severity = none # Underscores should be used to make large numbers readable — covered by SST1191 +dotnet_diagnostic.S2156.severity = none # "sealed" classes should not have "protected" members — covered by SST1427 +dotnet_diagnostic.S2219.severity = none # Runtime type checking should be simplified — covered by SST2007 dotnet_diagnostic.S2221.severity = none # "Exception" should not be caught -dotnet_diagnostic.S2292.severity = error # Trivial properties should be auto-implemented +dotnet_diagnostic.S2292.severity = none # Trivial properties should be auto-implemented — covered by SST1420 dotnet_diagnostic.S2325.severity = none # Methods and properties that don't access instance data should be static - DUPLICATE CA1822 -dotnet_diagnostic.S2333.severity = error # Redundant modifiers should not be used -dotnet_diagnostic.S2342.severity = error # Enumeration types should comply with a naming convention +dotnet_diagnostic.S2333.severity = none # Redundant modifiers should not be used — covered by SST1419/SST1491 +dotnet_diagnostic.S2342.severity = none # Enumeration types should comply with a naming convention — covered by SST1319 dotnet_diagnostic.S2344.severity = none # Enumeration type names should not have "Flags" or "Enum" suffixes - DUPLICATE CA1711 -dotnet_diagnostic.S2386.severity = error # Mutable fields should not be "public static" -dotnet_diagnostic.S2486.severity = error # Generic exceptions should not be ignored -dotnet_diagnostic.S2737.severity = error # "catch" clauses should do more than rethrow -dotnet_diagnostic.S2760.severity = error # Sequential tests should not check the same condition -dotnet_diagnostic.S3052.severity = error # Members should not be initialized to default values -dotnet_diagnostic.S3220.severity = error # Method calls should not resolve ambiguously to overloads with "params" -dotnet_diagnostic.S3234.severity = error # "GC.SuppressFinalize" should not be invoked for types without destructors -dotnet_diagnostic.S3235.severity = error # Redundant parentheses should not be used -dotnet_diagnostic.S3236.severity = error # Caller information arguments should not be provided explicitly -dotnet_diagnostic.S3240.severity = error # The simplest possible condition syntax should be used -dotnet_diagnostic.S3241.severity = error # Methods should not return values that are never used +dotnet_diagnostic.S2386.severity = none # Mutable fields should not be "public static" — covered by SST1499 +dotnet_diagnostic.S2486.severity = none # Generic exceptions should not be ignored — covered by SST1429 +dotnet_diagnostic.S2737.severity = none # "catch" clauses should do more than rethrow — covered by SST1470 +dotnet_diagnostic.S2760.severity = none # Sequential tests should not check the same condition — covered by SST1475 +dotnet_diagnostic.S3052.severity = none # Covered by PSH1403 (canonical) +dotnet_diagnostic.S3220.severity = none # Method calls should not resolve ambiguously to overloads with "params" — covered by SST2467 +dotnet_diagnostic.S3234.severity = none # Covered by PSH1008 (canonical) +dotnet_diagnostic.S3235.severity = none # Redundant parentheses should not be used — covered by SST1459 +dotnet_diagnostic.S3236.severity = none # Covered by SST1448 (canonical) +dotnet_diagnostic.S3240.severity = none # The simplest possible condition syntax should be used - duplicate of SST1198 +dotnet_diagnostic.S3241.severity = none # Methods should not return values that are never used -> off: needs whole-program analysis; not enforced here dotnet_diagnostic.S3242.severity = none # Method parameters should be declared with base types -dotnet_diagnostic.S3247.severity = error # Duplicate casts should not be made -dotnet_diagnostic.S3251.severity = error # Implementations should be provided for "partial" methods -dotnet_diagnostic.S3253.severity = error # Constructor and destructor declarations should not be redundant -dotnet_diagnostic.S3254.severity = error # Default parameter values should not be passed as arguments -dotnet_diagnostic.S3256.severity = error # "string.IsNullOrEmpty" should be used -dotnet_diagnostic.S3257.severity = error # Declarations and initializations should be as concise as possible -dotnet_diagnostic.S3260.severity = error # Non-derived "private" classes and records should be "sealed" -dotnet_diagnostic.S3261.severity = error # Namespaces should not be empty +dotnet_diagnostic.S3247.severity = none # Duplicate casts should not be made — covered by SST1175 +dotnet_diagnostic.S3251.severity = none # Implementations should be provided for "partial" methods — covered by SST2468 +dotnet_diagnostic.S3253.severity = none # Constructor and destructor declarations should not be redundant — covered by SST1433 +dotnet_diagnostic.S3254.severity = none # Default parameter values should not be passed as arguments — covered by SST1494 +dotnet_diagnostic.S3256.severity = none # "string.IsNullOrEmpty" should be used — covered by PSH1204 (style configurable) +dotnet_diagnostic.S3257.severity = none # Declarations and initializations should be as concise as possible -> replaced by SST2202 +dotnet_diagnostic.S3260.severity = none # Non-derived "private" classes and records should be "sealed" — covered by PSH1411 +dotnet_diagnostic.S3261.severity = none # Namespaces should not be empty — covered by SST1435 dotnet_diagnostic.S3267.severity = none # Loops should be simplified with "LINQ" expressions dotnet_diagnostic.S3376.severity = none # Attribute, EventArgs, and Exception type names should end with the type being extended - DUPLICATE CA1710 -dotnet_diagnostic.S3398.severity = error # "private" methods called only by inner classes should be moved to those classes -dotnet_diagnostic.S3400.severity = error # Methods should not return constants -dotnet_diagnostic.S3416.severity = error # Loggers should be named for their enclosing types -dotnet_diagnostic.S3440.severity = error # Variables should not be checked against the values they're about to be assigned -dotnet_diagnostic.S3441.severity = error # Redundant property names should be omitted in anonymous classes -dotnet_diagnostic.S3444.severity = error # Interfaces should not simply inherit from base interfaces with colliding members -dotnet_diagnostic.S3450.severity = error # Parameters with "[DefaultParameterValue]" attributes should also be marked "[Optional]" -dotnet_diagnostic.S3458.severity = error # Empty "case" clauses that fall through to the "default" should be omitted -dotnet_diagnostic.S3459.severity = error # Unassigned members should be removed -dotnet_diagnostic.S3532.severity = error # Empty "default" clauses should be removed -dotnet_diagnostic.S3604.severity = error # Member initializer values should not be redundant -dotnet_diagnostic.S3626.severity = none # Jump statements should not be redundant -dotnet_diagnostic.S3717.severity = error # Track use of "NotImplementedException" -dotnet_diagnostic.S3872.severity = error # Parameter names should not duplicate the names of their methods -dotnet_diagnostic.S3876.severity = error # Strings or integral types should be used for indexers -dotnet_diagnostic.S3878.severity = error # Arrays should not be created for params parameters -dotnet_diagnostic.S3897.severity = error # Classes that provide "Equals()" should implement "IEquatable" -dotnet_diagnostic.S3962.severity = none # "static readonly" constants should be "const" instead - DUPLICATE CA1802 +dotnet_diagnostic.S3398.severity = none # "private" methods called only by inner classes should be moved to those classes — covered by SST1498 +dotnet_diagnostic.S3400.severity = none # Methods should not return constants — covered by SST1493 +dotnet_diagnostic.S3416.severity = none # Loggers should be named for their enclosing types — covered by SST2443 +dotnet_diagnostic.S3440.severity = none # Variables should not be checked against the values they're about to be assigned — covered by SST1492 +dotnet_diagnostic.S3441.severity = none # Redundant property names should be omitted in anonymous classes — covered by SST1173 +dotnet_diagnostic.S3444.severity = none # Interfaces should not simply inherit from base interfaces with colliding members — covered by SST2320 +dotnet_diagnostic.S3450.severity = none # Parameters with "[DefaultParameterValue]" attributes should also be marked "[Optional]" -> replaced by obsolete (legacy DefaultParameterValue) +dotnet_diagnostic.S3458.severity = none # Empty "case" clauses that fall through to the "default" should be omitted — covered by SST1466 +dotnet_diagnostic.S3459.severity = none # Unassigned members should be removed - the compiler reports this as CS0649; the rule only ever fires on private never-assigned fields +dotnet_diagnostic.S3532.severity = none # Empty "default" clauses should be removed — covered by SST1179 +dotnet_diagnostic.S3604.severity = none # Member initializer values should not be redundant — covered by PSH1403 +dotnet_diagnostic.S3626.severity = none # Jump statements should not be redundant — covered by SST1174 +dotnet_diagnostic.S3717.severity = none # Track use of "NotImplementedException" -> replaced by SST2485 +dotnet_diagnostic.S3872.severity = none # Parameter names should not duplicate the names of their methods -> replaced by SST1320 +dotnet_diagnostic.S3876.severity = none # Strings or integral types should be used for indexers -> replaced by CA1043 +dotnet_diagnostic.S3878.severity = none # Arrays should not be created for params parameters — covered by PSH1018 +dotnet_diagnostic.S3897.severity = none # Classes that provide "Equals()" should implement "IEquatable" -> replaced by CA1067 +dotnet_diagnostic.S3962.severity = none # Covered by PSH1402 (canonical) dotnet_diagnostic.S3963.severity = none # "static" fields should be initialized inline - DUPLICATE CA1810 dotnet_diagnostic.S3967.severity = none # Multidimensional arrays should not be used - DUPLICATE CA1814 -dotnet_diagnostic.S4018.severity = error # All type parameters should be used in the parameter list to enable type inference -dotnet_diagnostic.S4022.severity = error # Enumerations should have "Int32" storage -dotnet_diagnostic.S4023.severity = none # Interfaces should not be empty -dotnet_diagnostic.S4026.severity = error # Assemblies should be marked with "NeutralResourcesLanguageAttribute" -dotnet_diagnostic.S4027.severity = error # Exceptions should provide standard constructors +dotnet_diagnostic.S4018.severity = none # All type parameters should be used in the parameter list to enable type inference — covered by SST2307 +dotnet_diagnostic.S4022.severity = none # Enumerations should have "Int32" storage — covered by SST2313 +dotnet_diagnostic.S4023.severity = none # Interfaces should not be empty — covered by SST1437 +dotnet_diagnostic.S4026.severity = none # Assemblies should be marked with "NeutralResourcesLanguageAttribute" -> replaced by CA1824 +dotnet_diagnostic.S4027.severity = none # Exceptions should provide standard constructors — covered by SST1488 dotnet_diagnostic.S4040.severity = none # Strings should be normalized to uppercase - DUPLICATE CA1308 dotnet_diagnostic.S4041.severity = none # Type names should not match namespaces - DUPLICATE CA1724 -dotnet_diagnostic.S4047.severity = error # Generics should be used when appropriate +dotnet_diagnostic.S4047.severity = none # Generics should be used when appropriate -> off: fuzzy prefer-generics suggestion; not enforced dotnet_diagnostic.S4049.severity = none # Properties should be preferred - DUPLICATE CA1024 -dotnet_diagnostic.S4052.severity = error # Types should not extend outdated base types +dotnet_diagnostic.S4052.severity = none # Types should not extend outdated base types -> replaced by obsolete dotnet_diagnostic.S4056.severity = none # Overloads with a "CultureInfo" or an "IFormatProvider" parameter should be used - DUPLICATE CA1305 -dotnet_diagnostic.S4058.severity = error # Overloads with a "StringComparison" parameter should be used +dotnet_diagnostic.S4058.severity = none # Covered by PSH1207 (canonical) dotnet_diagnostic.S4060.severity = none # Non-abstract attributes should be sealed - DUPLICATE CA1813 -dotnet_diagnostic.S4061.severity = error # "params" should be used instead of "varargs" +dotnet_diagnostic.S4061.severity = none # "params" should be used instead of "varargs" -> replaced by obsolete (__arglist varargs) dotnet_diagnostic.S4069.severity = none # Operator overloads should have named alternatives - DUPLICATE CA2225 -dotnet_diagnostic.S4136.severity = error # Method overloads should be grouped together -dotnet_diagnostic.S4201.severity = error # Null checks should not be combined with "is" operator checks -dotnet_diagnostic.S4225.severity = error # Extension methods should not extend "object" +dotnet_diagnostic.S4136.severity = none # Method overloads should be grouped together — covered by SST1218 +dotnet_diagnostic.S4201.severity = none # Null checks should not be combined with "is" operator checks — covered by SST2018 +dotnet_diagnostic.S4225.severity = none # Extension methods should not extend "object" — covered by SST1706 dotnet_diagnostic.S4226.severity = none # Extensions should be in separate namespaces dotnet_diagnostic.S4261.severity = none # Methods should be named according to their synchronicities - Async suffix not used -dotnet_diagnostic.S4663.severity = error # Comments should not be empty +dotnet_diagnostic.S4663.severity = none # Covered by SST1120 (canonical) dotnet_diagnostic.S6513.severity = none # "ExcludeFromCodeCoverage" attributes should include a justification - not available on net462 and older TFMs -dotnet_diagnostic.S6585.severity = error # Don't hardcode the format when turning dates and times to strings -dotnet_diagnostic.S6588.severity = error # Use the "UnixEpoch" field instead of creating "DateTime" instances that point to the beginning of the Unix epoch -dotnet_diagnostic.S6602.severity = none # "Find" method should be used instead of the "FirstOrDefault" extension - DUPLICATE CA1826 -dotnet_diagnostic.S6603.severity = error # The collection-specific "TrueForAll" method should be used instead of the "All" extension -dotnet_diagnostic.S6605.severity = error # Collection-specific "Exists" method should be used instead of the "Any" extension -dotnet_diagnostic.S6607.severity = error # The collection should be filtered before sorting by using "Where" before "OrderBy" -dotnet_diagnostic.S6608.severity = none # Prefer indexing instead of "Enumerable" methods on types implementing "IList" - DUPLICATE CA1826 -dotnet_diagnostic.S6609.severity = error # "Min/Max" properties of "Set" types should be used instead of the "Enumerable" extension methods -dotnet_diagnostic.S6610.severity = error # "StartsWith" and "EndsWith" overloads that take a "char" should be used instead of the ones that take a "string" -dotnet_diagnostic.S6612.severity = error # The lambda parameter should be used instead of capturing arguments in "ConcurrentDictionary" methods -dotnet_diagnostic.S6613.severity = error # "First" and "Last" properties of "LinkedList" should be used instead of the "First()" and "Last()" extension methods -dotnet_diagnostic.S6617.severity = error # "Contains" should be used instead of "Any" for simple equality checks -dotnet_diagnostic.S6618.severity = error # "string.Create" should be used instead of "FormattableString" -dotnet_diagnostic.S6664.severity = error # The code block contains too many logging calls -dotnet_diagnostic.S6667.severity = error # Logging in a catch clause should pass the caught exception as a parameter. -dotnet_diagnostic.S6668.severity = error # Logging arguments should be passed to the correct parameter -dotnet_diagnostic.S6669.severity = error # Logger field or property name should comply with a naming convention -dotnet_diagnostic.S6670.severity = error # "Trace.Write" and "Trace.WriteLine" should not be used -dotnet_diagnostic.S6672.severity = error # Generic logger injection should match enclosing type -dotnet_diagnostic.S6675.severity = error # "Trace.WriteLineIf" should not be used with "TraceSwitch" levels -dotnet_diagnostic.S6678.severity = error # Use PascalCase for named placeholders -dotnet_diagnostic.S818.severity = error # Literal suffixes should be upper case - -################### -# SonarAnalyzer (Sxxxx) - Info Code Smell -################### -dotnet_diagnostic.S1133.severity = error # Deprecated code should be removed -dotnet_diagnostic.S1135.severity = error # Track uses of "TODO" tags +dotnet_diagnostic.S6585.severity = none # Don't hardcode the format when turning dates and times to strings — covered by SST2445 +dotnet_diagnostic.S6588.severity = none # Use the "UnixEpoch" field instead of creating "DateTime" instances that point to the beginning of the Unix epoch — covered by PSH1413 +dotnet_diagnostic.S6594.severity = none # Covered by PSH1406 (canonical) +dotnet_diagnostic.S6602.severity = none # Covered by PSH1110 (canonical) +dotnet_diagnostic.S6603.severity = none # Covered by PSH1110 (canonical) +dotnet_diagnostic.S6605.severity = none # Covered by PSH1110 (canonical) +dotnet_diagnostic.S6607.severity = none # The collection should be filtered before sorting — covered by PSH1107 +dotnet_diagnostic.S6608.severity = none # Covered by PSH1106 (canonical) +dotnet_diagnostic.S6609.severity = none # "Min/Max" properties of "Set" types should be used instead of the "Enumerable" extension methods — covered by PSH1122 +dotnet_diagnostic.S6610.severity = none # Covered by PSH1201 (canonical) +dotnet_diagnostic.S6612.severity = none # The lambda parameter should be used instead of capturing arguments in "ConcurrentDictionary" methods — covered by PSH1006 +dotnet_diagnostic.S6613.severity = none # "First" and "Last" properties of "LinkedList" should be used instead of the "First()" and "Last()" extension methods — covered by PSH1124 +dotnet_diagnostic.S6617.severity = none # Covered by PSH1111 (canonical) +dotnet_diagnostic.S6618.severity = none # "string.Create" should be used instead of "FormattableString" — covered by PSH1209 +dotnet_diagnostic.S6664.severity = none # The code block contains too many logging calls -> off: fuzzy too-many-logging-calls metric; not enforced +dotnet_diagnostic.S6667.severity = none # Logging in a catch clause should pass the caught exception as a parameter. — covered by SST2438 +dotnet_diagnostic.S6668.severity = none # Logging arguments should be passed to the correct parameter — covered by SST2439 +dotnet_diagnostic.S6669.severity = none # Logger field or property name should comply with a naming convention -> replaced by SST2601 +dotnet_diagnostic.S6670.severity = none # "Trace.Write" and "Trace.WriteLine" should not be used — covered by SST2600 +dotnet_diagnostic.S6672.severity = none # Generic logger injection should match enclosing type — covered by SST2443 +dotnet_diagnostic.S6675.severity = none # "Trace.WriteLineIf" should not be used with "TraceSwitch" levels -> off: niche TraceSwitch misuse; not enforced here +dotnet_diagnostic.S6678.severity = none # Use PascalCase for named placeholders -> replaced by CA1727 +dotnet_diagnostic.S818.severity = none # Literal suffixes should be upper case — covered by SST2244 + +# Informational code smells +dotnet_diagnostic.S1133.severity = none # Deprecated code should be removed — covered by SST2310 +dotnet_diagnostic.S1135.severity = none # Track uses of "TODO" tags -> off: FIXME comment tracker; not enforced here dotnet_diagnostic.S1309.severity = none # Track uses of in-source issue suppressions -################### -# SonarAnalyzer (Sxxxx) - Uncategorized -################### +# Uncategorized dotnet_diagnostic.S9999-cpd.severity = error # Copy-paste token calculator dotnet_diagnostic.S9999-log.severity = error # Log generator dotnet_diagnostic.S9999-metadata.severity = error # File metadata generator @@ -1946,36 +2622,30 @@ dotnet_diagnostic.S9999-testMethodDeclaration.severity = error # Test method dec dotnet_diagnostic.S9999-token-type.severity = error # Token type calculator dotnet_diagnostic.S9999-warning.severity = error # Analysis Warning generator -################### -# SonarAnalyzer (Sxxxx) - Critical Security Hotspot -################### +# Critical security hotspots dotnet_diagnostic.S2245.severity = none # Using pseudorandom number generators (PRNGs) is security-sensitive - DUPLICATE CA5394 -dotnet_diagnostic.S2257.severity = error # Using non-standard cryptographic algorithms is security-sensitive -dotnet_diagnostic.S4502.severity = error # Disabling CSRF protections is security-sensitive -dotnet_diagnostic.S4790.severity = error # Using weak hashing algorithms is security-sensitive -dotnet_diagnostic.S4792.severity = error # Configuring loggers is security-sensitive -dotnet_diagnostic.S5042.severity = error # Expanding archive files without controlling resource consumption is security-sensitive -dotnet_diagnostic.S5332.severity = error # Using clear-text protocols is security-sensitive -dotnet_diagnostic.S5443.severity = error # Using publicly writable directories is security-sensitive - -################### -# SonarAnalyzer (Sxxxx) - Major Security Hotspot -################### -dotnet_diagnostic.S1313.severity = error # Using hardcoded IP addresses is security-sensitive -dotnet_diagnostic.S2077.severity = error # Formatting SQL queries is security-sensitive -dotnet_diagnostic.S5693.severity = error # Allowing requests with excessive content length is security-sensitive -dotnet_diagnostic.S5753.severity = error # Disabling ASP.NET "Request Validation" feature is security-sensitive -dotnet_diagnostic.S5766.severity = error # Creating Serializable objects without data validation checks is security-sensitive -dotnet_diagnostic.S6444.severity = error # Not specifying a timeout for regular expressions is security-sensitive -dotnet_diagnostic.S6640.severity = error # Using unsafe code blocks is security-sensitive - -################### -# SonarAnalyzer (Sxxxx) - Minor Security Hotspot -################### -dotnet_diagnostic.S2092.severity = error # Creating cookies without the "secure" flag is security-sensitive -dotnet_diagnostic.S3330.severity = error # Creating cookies without the "HttpOnly" flag is security-sensitive -dotnet_diagnostic.S4507.severity = error # Delivering code in production with debug features activated is security-sensitive -dotnet_diagnostic.S5122.severity = error # Having a permissive Cross-Origin Resource Sharing policy is security-sensitive +dotnet_diagnostic.S2257.severity = none # Using non-standard cryptographic algorithms is security-sensitive -> replaced by SES1007 +dotnet_diagnostic.S4502.severity = none # Disabling CSRF protections is security-sensitive -> replaced by in-box ASP.NET antiforgery analyzer +dotnet_diagnostic.S4790.severity = none # Using weak hashing algorithms is security-sensitive -> replaced by CA5350/CA5351 +dotnet_diagnostic.S4792.severity = none # Configuring loggers is security-sensitive -> off: logging-configuration audit hotspot; not enforced here +dotnet_diagnostic.S5042.severity = none # Expanding archive files without controlling resource consumption is security-sensitive -> off: unbounded decompression; needs taint analysis, out of scope +dotnet_diagnostic.S5332.severity = none # Using clear-text protocols is security-sensitive -> replaced by SES1106 +dotnet_diagnostic.S5443.severity = none # Using publicly writable directories is security-sensitive -> replaced by SES1308 + +# Major security hotspots +dotnet_diagnostic.S1313.severity = none # Using hardcoded IP addresses is security-sensitive -> off: hardcoded-IP heuristic; too noisy to enforce +dotnet_diagnostic.S2077.severity = none # Formatting SQL queries is security-sensitive -> replaced by CA2100 +dotnet_diagnostic.S5693.severity = none # Allowing requests with excessive content length is security-sensitive -> replaced by SES1505 +dotnet_diagnostic.S5753.severity = none # Disabling ASP.NET "Request Validation" feature is security-sensitive -> replaced by obsolete (legacy ASP.NET request validation) +dotnet_diagnostic.S5766.severity = none # Creating Serializable objects without data validation checks is security-sensitive -> off: legacy BinaryFormatter deserialization; obsolete path, not used here +dotnet_diagnostic.S6444.severity = none # Not specifying a timeout for regular expressions is security-sensitive -> replaced by SES1509 +dotnet_diagnostic.S6640.severity = none # Using unsafe code blocks is security-sensitive -> off: unsafe-code audit; not enforced here + +# Minor security hotspots +dotnet_diagnostic.S2092.severity = none # Creating cookies without the "secure" flag is security-sensitive -> replaced by CA5382 +dotnet_diagnostic.S3330.severity = none # Creating cookies without the "HttpOnly" flag is security-sensitive -> replaced by CA5383 +dotnet_diagnostic.S4507.severity = none # Delivering code in production with debug features activated is security-sensitive -> off: debug features in production; partly covered by SES1506, rest not enforced +dotnet_diagnostic.S5122.severity = none # Having a permissive Cross-Origin Resource Sharing policy is security-sensitive -> replaced by SES1501 ############################################# # JetBrains ReSharper / Rider Inspections @@ -2043,7 +2713,7 @@ resharper_redundant_to_string_call_highlighting = none # handled by RCS1097 ################### # ReSharper - Naming (matches SA/CA naming rules) ################### -resharper_inconsistent_naming_highlighting = error # partially handled by SA1300 family but IDE1006 isn't enabled; keep ReSharper active +resharper_inconsistent_naming_highlighting = none # too many false positives on test/fixture naming; SA1300 family covers the real cases ################### # ReSharper - Unused code (matches CA1801 / CA1823 / IDE0051-0052) @@ -2158,4 +2828,11 @@ indent_size = 2 end_of_line = lf [*.{cmd, bat}] -end_of_line = crlf +end_of_line = lf + +############################################# +# Test projects (TUnit) +############################################# +# TUnit instantiates test classes per test, so they must remain instance classes and +# cannot be marked static — even when a partial declaration happens to hold only static +# members (the instance [Test] methods live in sibling partial files). diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 1b01a16..024c2e9 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -90,6 +90,15 @@ + + + + + + + + true @@ -112,12 +121,11 @@ - + + + - - - diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 7fbffe3..15539ec 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -6,48 +6,65 @@ - 10.0.41 + 10.0.90 9.0.120 + + + 3.39.2 + + - - - + + + - + - - - + + + - - + + + - + + + - - + + @@ -58,7 +75,7 @@ - - + + diff --git a/src/ReactiveUI.Binding.Analyzer/Analyzers/AnalyzerHelpers.cs b/src/ReactiveUI.Binding.Analyzer/Analyzers/AnalyzerHelpers.cs index d0310d0..8a8b22c 100644 --- a/src/ReactiveUI.Binding.Analyzer/Analyzers/AnalyzerHelpers.cs +++ b/src/ReactiveUI.Binding.Analyzer/Analyzers/AnalyzerHelpers.cs @@ -8,21 +8,17 @@ namespace ReactiveUI.Binding.Analyzer.Analyzers; -/// -/// Shared helper methods for analyzers. No LINQ, manual loops. -/// +/// Shared helper methods for analyzers. No LINQ, manual loops. internal static class AnalyzerHelpers { - /// - /// Checks if a method symbol belongs to our generated extension class. - /// + /// Checks if a method symbol belongs to our generated extension class. /// The method symbol to check. /// true if the method is from our generated extension class. [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool IsBindingExtensionMethod(IMethodSymbol methodSymbol) { var containingType = methodSymbol.ContainingType; - if (containingType == null) + if (containingType is null) { return false; } @@ -32,18 +28,14 @@ internal static bool IsBindingExtensionMethod(IMethodSymbol methodSymbol) or SourceGenerators.Constants.StubExtensionClassName; } - /// - /// Checks if an expression is an inline lambda (not a variable reference or method call). - /// + /// Checks if an expression is an inline lambda (not a variable reference or method call). /// The expression to check. /// true if the expression is an inline lambda. [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool IsInlineLambda(ExpressionSyntax expression) => expression is SimpleLambdaExpressionSyntax or ParenthesizedLambdaExpressionSyntax; - /// - /// Checks if a type supports before-change notifications based on its notification mechanism. - /// + /// Checks if a type supports before-change notifications based on its notification mechanism. /// The type to check. /// The current compilation for type resolution. /// Output: the name of the detected mechanism. @@ -117,15 +109,7 @@ internal static bool HasBeforeChangeSupport( /// The method symbol to extract from. /// The first type argument as , or null. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static INamedTypeSymbol? ExtractFirstTypeArgument(IMethodSymbol methodSymbol) - { - if (methodSymbol.TypeArguments.Length == 0) - { - return null; - } - - return methodSymbol.TypeArguments[0] as INamedTypeSymbol; - } + internal static INamedTypeSymbol? ExtractFirstTypeArgument(IMethodSymbol methodSymbol) => methodSymbol.TypeArguments.IsEmpty ? null : methodSymbol.TypeArguments[0] as INamedTypeSymbol; /// /// Determines whether a method's first type argument lacks any observable notification mechanism. @@ -141,12 +125,7 @@ internal static bool LacksObservableMechanism( out INamedTypeSymbol? sourceType) { sourceType = ExtractFirstTypeArgument(methodSymbol); - if (sourceType == null) - { - return false; - } - - return !TypeAnalyzer.HasObservableMechanism(sourceType, compilation); + return sourceType is null ? false : !TypeAnalyzer.HasObservableMechanism(sourceType, compilation); } /// @@ -166,12 +145,7 @@ internal static bool LacksBeforeChangeSupport( { mechanism = string.Empty; receiverType = ExtractFirstTypeArgument(methodSymbol); - if (receiverType == null) - { - return false; - } - - return !HasBeforeChangeSupport(receiverType, compilation, out mechanism); + return receiverType is null ? false : !HasBeforeChangeSupport(receiverType, compilation, out mechanism); } /// @@ -190,24 +164,17 @@ internal static bool ImplementsDataErrorInfo( out INamedTypeSymbol? sourceType) { sourceType = ExtractFirstTypeArgument(methodSymbol); - if (sourceType == null) + if (sourceType is null) { return false; } var dataErrorInfo = compilation.GetTypeByMetadataName(SourceGenerators.Constants.INotifyDataErrorInfoMetadataName); - if (dataErrorInfo == null) - { - return false; - } - - return ImplementsInterface(sourceType, dataErrorInfo); + return dataErrorInfo is null ? false : ImplementsInterface(sourceType, dataErrorInfo); } - /// - /// Determines whether a type implements a specific interface. - /// + /// Determines whether a type implements a specific interface. /// The type symbol to check. /// The interface symbol to look for. /// true if the type implements the specified interface; otherwise, false. @@ -225,16 +192,14 @@ internal static bool ImplementsInterface(INamedTypeSymbol typeSymbol, INamedType return false; } - /// - /// Determines whether a type inherits from a specific base type. - /// + /// Determines whether a type inherits from a specific base type. /// The type symbol to check. /// The base type symbol to look for in the inheritance hierarchy. /// true if the type inherits from the specified base type; otherwise, false. internal static bool InheritsFrom(INamedTypeSymbol typeSymbol, INamedTypeSymbol baseTypeSymbol) { var current = typeSymbol.BaseType; - while (current != null) + while (current is not null) { if (SymbolEqualityComparer.Default.Equals(current, baseTypeSymbol)) { @@ -265,7 +230,7 @@ private static bool Matches( bool byInterface) { var target = compilation.GetTypeByMetadataName(metadataName); - if (target == null) + if (target is null) { return false; } diff --git a/src/ReactiveUI.Binding.Analyzer/Analyzers/BindingInvocationAnalyzer.cs b/src/ReactiveUI.Binding.Analyzer/Analyzers/BindingInvocationAnalyzer.cs index 9fd0639..271d0fa 100644 --- a/src/ReactiveUI.Binding.Analyzer/Analyzers/BindingInvocationAnalyzer.cs +++ b/src/ReactiveUI.Binding.Analyzer/Analyzers/BindingInvocationAnalyzer.cs @@ -23,15 +23,14 @@ public class BindingInvocationAnalyzer : DiagnosticAnalyzer { /// public override ImmutableArray SupportedDiagnostics => - [ - DiagnosticWarnings.NonInlineLambda, - DiagnosticWarnings.PrivateMember, - DiagnosticWarnings.NoBeforeChangeSupport, - DiagnosticWarnings.ValidationNotGenerated, - DiagnosticWarnings.UnsupportedPathSegment, - DiagnosticWarnings.NoBindableEvent, - DiagnosticWarnings.InvalidInteractionType - ]; + ImmutableArray.Create( + DiagnosticWarnings.NonInlineLambda, + DiagnosticWarnings.PrivateMember, + DiagnosticWarnings.NoBeforeChangeSupport, + DiagnosticWarnings.ValidationNotGenerated, + DiagnosticWarnings.UnsupportedPathSegment, + DiagnosticWarnings.NoBindableEvent, + DiagnosticWarnings.InvalidInteractionType); /// public override void Initialize(AnalysisContext context) @@ -39,14 +38,12 @@ public override void Initialize(AnalysisContext context) ArgumentExceptionHelper.ThrowIfNull(context); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.EnableConcurrentExecution(); - context.RegisterOperationAction(AnalyzeInvocation, OperationKind.Invocation); + context.RegisterOperationAction(static operationContext => AnalyzeInvocation(in operationContext), OperationKind.Invocation); } - /// - /// Analyzes a method invocation operation for binding-related diagnostics. - /// + /// Analyzes a method invocation operation for binding-related diagnostics. /// The operation analysis context. - internal static void AnalyzeInvocation(OperationAnalysisContext context) + internal static void AnalyzeInvocation(in OperationAnalysisContext context) { var invocationOp = (IInvocationOperation)context.Operation; @@ -95,14 +92,12 @@ internal static void AnalyzeInvocation(OperationAnalysisContext context) CheckBindableEvent(context, invocationOp); } - /// - /// Checks for RXUIBIND001: Expression arguments that are not inline lambdas. - /// + /// Checks for RXUIBIND001: Expression arguments that are not inline lambdas. /// The operation analysis context. /// The invocation arguments to inspect. /// The name of the method being invoked. internal static void CheckNonInlineLambda( - OperationAnalysisContext context, + in OperationAnalysisContext context, ImmutableArray arguments, string methodName) { @@ -133,13 +128,11 @@ internal static void CheckNonInlineLambda( } } - /// - /// Checks for RXUIBIND003: Lambda expressions that access private or protected members. - /// + /// Checks for RXUIBIND003: Lambda expressions that access private or protected members. /// The operation analysis context. /// The invocation arguments to inspect. internal static void CheckPrivateMember( - OperationAnalysisContext context, + in OperationAnalysisContext context, ImmutableArray arguments) { for (var i = 0; i < arguments.Length; i++) @@ -152,7 +145,7 @@ internal static void CheckPrivateMember( // Walk the lambda body looking for member accesses var body = GetLambdaBody(lambda); - if (body == null) + if (body is null) { continue; } @@ -160,7 +153,7 @@ internal static void CheckPrivateMember( var current = body; while (current is MemberAccessExpressionSyntax memberAccess) { - var memberSymbol = context.Operation.SemanticModel!.GetSymbolInfo(memberAccess).Symbol; + var memberSymbol = context.Operation.SemanticModel!.GetSymbolInfo(memberAccess, context.CancellationToken).Symbol; if (memberSymbol is { DeclaredAccessibility: Accessibility.Private or Accessibility.Protected }) { context.ReportDiagnostic( @@ -176,14 +169,12 @@ internal static void CheckPrivateMember( } } - /// - /// Checks for RXUIBIND004: WhenChanging invocations on types that do not support before-change notifications. - /// + /// Checks for RXUIBIND004: WhenChanging invocations on types that do not support before-change notifications. /// The operation analysis context. /// The invocation operation being analyzed. /// The method symbol of the invocation target. internal static void CheckBeforeChangeSupport( - OperationAnalysisContext context, + in OperationAnalysisContext context, IInvocationOperation invocationOp, IMethodSymbol methodSymbol) { @@ -211,7 +202,7 @@ internal static void CheckBeforeChangeSupport( /// The operation analysis context. /// The invocation operation being analyzed. internal static void CheckValidationSupport( - OperationAnalysisContext context, + in OperationAnalysisContext context, IInvocationOperation invocationOp) { if (!AnalyzerHelpers.ImplementsDataErrorInfo( @@ -236,7 +227,7 @@ internal static void CheckValidationSupport( /// The operation analysis context. /// The invocation operation being analyzed. internal static void CheckInteractionType( - OperationAnalysisContext context, + in OperationAnalysisContext context, IInvocationOperation invocationOp) { // Find the propertyName argument (the Expression>> parameter) @@ -257,19 +248,19 @@ internal static void CheckInteractionType( // Get the lambda body return type var body = GetLambdaBody(lambda); - if (body == null) + if (body is null) { break; } - var typeInfo = context.Operation.SemanticModel!.GetTypeInfo(body); - if (typeInfo.Type == null) + var typeInfo = context.Operation.SemanticModel!.GetTypeInfo(body, context.CancellationToken); + if (typeInfo.Type is null) { break; } var interactionType = context.Compilation.GetTypeByMetadataName(Constants.IInteractionMetadataName); - if (interactionType == null) + if (interactionType is null) { break; } @@ -296,7 +287,7 @@ internal static void CheckInteractionType( /// The operation analysis context. /// The invocation operation being analyzed. internal static void CheckBindableEvent( - OperationAnalysisContext context, + in OperationAnalysisContext context, IInvocationOperation invocationOp) { _ = invocationOp.TargetMethod; @@ -323,12 +314,12 @@ internal static void CheckBindableEvent( } var body = GetLambdaBody(lambda); - if (body == null) + if (body is null) { break; } - var typeInfo = context.Operation.SemanticModel!.GetTypeInfo(body); + var typeInfo = context.Operation.SemanticModel!.GetTypeInfo(body, context.CancellationToken); if (typeInfo.Type is not INamedTypeSymbol controlType) { break; @@ -347,9 +338,7 @@ internal static void CheckBindableEvent( } } - /// - /// Determines whether a type implements a specific open generic interface. - /// + /// Determines whether a type implements a specific open generic interface. /// The type symbol to check. /// The open generic interface to look for (e.g., IInteraction<,>). /// true if the type implements the specified open generic interface; otherwise, false. @@ -381,7 +370,7 @@ internal static bool ImplementsOpenGenericInterface(ITypeSymbol type, INamedType /// The operation analysis context. /// The invocation arguments to inspect. internal static void CheckUnsupportedPathSegment( - OperationAnalysisContext context, + in OperationAnalysisContext context, ImmutableArray arguments) { for (var i = 0; i < arguments.Length; i++) @@ -404,7 +393,7 @@ internal static void CheckUnsupportedPathSegment( var body = GetLambdaBody(lambda); - if (body == null) + if (body is null) { continue; } @@ -413,17 +402,15 @@ internal static void CheckUnsupportedPathSegment( } } - /// - /// Walks a member access chain looking for unsupported path segments (method calls, indexers, or fields). - /// + /// Walks a member access chain looking for unsupported path segments (method calls, indexers, or fields). /// The operation analysis context. /// The expression to walk. internal static void WalkForUnsupportedSegments( - OperationAnalysisContext context, + in OperationAnalysisContext context, ExpressionSyntax expression) { var current = expression; - while (current != null) + while (current is not null) { if (current is InvocationExpressionSyntax invocation) { @@ -450,7 +437,7 @@ internal static void WalkForUnsupportedSegments( if (current is MemberAccessExpressionSyntax memberAccess) { // Check if the member is a field - var memberSymbol = context.Operation.SemanticModel!.GetSymbolInfo(memberAccess).Symbol; + var memberSymbol = context.Operation.SemanticModel!.GetSymbolInfo(memberAccess, context.CancellationToken).Symbol; if (memberSymbol is IFieldSymbol { IsConst: false }) { context.ReportDiagnostic( @@ -470,11 +457,8 @@ internal static void WalkForUnsupportedSegments( } } - /// - /// Extracts the body expression from a lambda expression syntax node. - /// Only and - /// exist in Roslyn's C# syntax model. - /// + /// Extracts the body expression from a lambda expression syntax node. + /// Only and exist in Roslyn's C# syntax model. /// The lambda expression syntax node to extract the body from. /// /// The body as an , or null if the lambda body is a block statement. @@ -491,9 +475,7 @@ internal static void WalkForUnsupportedSegments( return parenthesized.Body as ExpressionSyntax; } - /// - /// Determines whether a non-empty constant toEvent argument was explicitly supplied. - /// + /// Determines whether a non-empty constant toEvent argument was explicitly supplied. /// The invocation arguments to inspect. /// true if a non-empty toEvent string was specified; otherwise, false. private static bool IsToEventSpecified(ImmutableArray arguments) diff --git a/src/ReactiveUI.Binding.Analyzer/Analyzers/TypeAnalyzer.cs b/src/ReactiveUI.Binding.Analyzer/Analyzers/TypeAnalyzer.cs index 6064bc2..51c960f 100644 --- a/src/ReactiveUI.Binding.Analyzer/Analyzers/TypeAnalyzer.cs +++ b/src/ReactiveUI.Binding.Analyzer/Analyzers/TypeAnalyzer.cs @@ -11,16 +11,13 @@ namespace ReactiveUI.Binding.Analyzer.Analyzers; -/// -/// Analyzes types used in binding invocations to detect types with no observable properties. -/// Reports RXUIBIND002. -/// +/// Analyzes types used in binding invocations to detect types with no observable properties. Reports RXUIBIND002. [DiagnosticAnalyzer(LanguageNames.CSharp)] public class TypeAnalyzer : DiagnosticAnalyzer { /// public override ImmutableArray SupportedDiagnostics => - [DiagnosticWarnings.NoObservableProperties]; + ImmutableArray.Create(DiagnosticWarnings.NoObservableProperties); /// public override void Initialize(AnalysisContext context) @@ -28,7 +25,7 @@ public override void Initialize(AnalysisContext context) ArgumentExceptionHelper.ThrowIfNull(context); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.EnableConcurrentExecution(); - context.RegisterOperationAction(AnalyzeInvocation, OperationKind.Invocation); + context.RegisterOperationAction(static operationContext => AnalyzeInvocation(in operationContext), OperationKind.Invocation); } /// @@ -36,7 +33,7 @@ public override void Initialize(AnalysisContext context) /// has any observable property notification mechanism. /// /// The operation analysis context. - internal static void AnalyzeInvocation(OperationAnalysisContext context) + internal static void AnalyzeInvocation(in OperationAnalysisContext context) { var invocationOp = (IInvocationOperation)context.Operation; @@ -117,7 +114,7 @@ private static bool InheritsObservableBaseType(INamedTypeSymbol typeSymbol, Comp ]; var current = typeSymbol.BaseType; - while (current != null) + while (current is not null) { if (MatchesAny(current, baseTypes)) { @@ -130,9 +127,7 @@ private static bool InheritsObservableBaseType(INamedTypeSymbol typeSymbol, Comp return false; } - /// - /// Determines whether equals any of the (possibly null) candidate symbols. - /// + /// Determines whether equals any of the (possibly null) candidate symbols. /// The symbol to compare. /// The candidate symbols; null entries are skipped. /// true if matches a non-null candidate; otherwise, false. @@ -140,7 +135,7 @@ private static bool MatchesAny(ISymbol symbol, INamedTypeSymbol?[] candidates) { for (var i = 0; i < candidates.Length; i++) { - if (candidates[i] != null && SymbolEqualityComparer.Default.Equals(symbol, candidates[i])) + if (candidates[i] is not null && SymbolEqualityComparer.Default.Equals(symbol, candidates[i])) { return true; } diff --git a/src/ReactiveUI.Binding.Analyzer/ReactiveUI.Binding.Analyzer.csproj b/src/ReactiveUI.Binding.Analyzer/ReactiveUI.Binding.Analyzer.csproj index 3471ccb..5d92741 100644 --- a/src/ReactiveUI.Binding.Analyzer/ReactiveUI.Binding.Analyzer.csproj +++ b/src/ReactiveUI.Binding.Analyzer/ReactiveUI.Binding.Analyzer.csproj @@ -13,10 +13,13 @@ + - - + + diff --git a/src/ReactiveUI.Binding.Maui/BooleanToVisibilityHints.cs b/src/ReactiveUI.Binding.Maui/BooleanToVisibilityHints.cs index edc8c32..8dd383e 100644 --- a/src/ReactiveUI.Binding.Maui/BooleanToVisibilityHints.cs +++ b/src/ReactiveUI.Binding.Maui/BooleanToVisibilityHints.cs @@ -4,24 +4,16 @@ namespace ReactiveUI.Binding.Maui; -/// -/// Enum that hints at the visibility of a UI element. -/// +/// Enum that hints at the visibility of a UI element. [Flags] public enum BooleanToVisibilityHints { - /// - /// Do not modify the boolean type conversion from its default action of using Visibility.Collapsed. - /// + /// Do not modify the boolean type conversion from its default action of using Visibility.Collapsed. None = 0, - /// - /// Inverse the action of the boolean type conversion; when true, collapse the visibility. - /// + /// Inverse the action of the boolean type conversion; when true, collapse the visibility. Inverse = 1 << 1, - /// - /// Use the Hidden value rather than Collapsed (MAUI only; ignored on WinUI where Hidden is not available). - /// + /// Use the Hidden value rather than Collapsed (MAUI only; ignored on WinUI where Hidden is not available). UseHidden = 1 << 2 } diff --git a/src/ReactiveUI.Binding.Maui/BooleanToVisibilityTypeConverter.cs b/src/ReactiveUI.Binding.Maui/BooleanToVisibilityTypeConverter.cs index 6b1ad10..4f01a91 100644 --- a/src/ReactiveUI.Binding.Maui/BooleanToVisibilityTypeConverter.cs +++ b/src/ReactiveUI.Binding.Maui/BooleanToVisibilityTypeConverter.cs @@ -10,9 +10,7 @@ namespace ReactiveUI.Binding.Maui; -/// -/// Converts to . -/// +/// Converts to . /// /// /// The conversion supports a as the conversion hint parameter: diff --git a/src/ReactiveUI.Binding.Maui/Builder/MauiBindingBuilderExtensions.cs b/src/ReactiveUI.Binding.Maui/Builder/MauiBindingBuilderExtensions.cs index b34d71f..ed29a95 100644 --- a/src/ReactiveUI.Binding.Maui/Builder/MauiBindingBuilderExtensions.cs +++ b/src/ReactiveUI.Binding.Maui/Builder/MauiBindingBuilderExtensions.cs @@ -7,30 +7,36 @@ namespace ReactiveUI.Binding.Maui.Builder; -/// -/// MAUI-specific extensions for the ReactiveUI.Binding builder. -/// +/// MAUI-specific extensions for the ReactiveUI.Binding builder. public static class MauiBindingBuilderExtensions { - /// - /// Configures ReactiveUI.Binding for MAUI platform, registering WinUI DependencyProperty - /// observation (on Windows) and Visibility converters. - /// + /// Provides WithMaui extension members for . /// The builder instance. - /// The builder instance for chaining. - public static IReactiveUIBindingBuilder WithMaui(this IReactiveUIBindingBuilder builder) + extension(IAppBuilder builder) { - ArgumentExceptionHelper.ThrowIfNull(builder); - - return builder.WithPlatformModule(new MauiBindingModule()); + /// + /// Configures ReactiveUI.Binding for MAUI platform, registering WinUI DependencyProperty + /// observation (on Windows) and Visibility converters. + /// + /// The builder instance for chaining. + public IReactiveUIBindingBuilder WithMaui() => + ((IReactiveUIBindingBuilder)builder).WithMaui(); } - /// - /// Configures ReactiveUI.Binding for MAUI platform, registering WinUI DependencyProperty - /// observation (on Windows) and Visibility converters. - /// + /// Provides WithMaui extension members for . /// The builder instance. - /// The builder instance for chaining. - public static IReactiveUIBindingBuilder WithMaui(this IAppBuilder builder) => - ((IReactiveUIBindingBuilder)builder).WithMaui(); + extension(IReactiveUIBindingBuilder builder) + { + /// + /// Configures ReactiveUI.Binding for MAUI platform, registering WinUI DependencyProperty + /// observation (on Windows) and Visibility converters. + /// + /// The builder instance for chaining. + public IReactiveUIBindingBuilder WithMaui() + { + ArgumentExceptionHelper.ThrowIfNull(builder); + + return builder.WithPlatformModule(new MauiBindingModule()); + } + } } diff --git a/src/ReactiveUI.Binding.Maui/DependencyObjectObservableForProperty.cs b/src/ReactiveUI.Binding.Maui/DependencyObjectObservableForProperty.cs index 70f9e4a..b5e944e 100644 --- a/src/ReactiveUI.Binding.Maui/DependencyObjectObservableForProperty.cs +++ b/src/ReactiveUI.Binding.Maui/DependencyObjectObservableForProperty.cs @@ -6,6 +6,7 @@ using System.Globalization; using System.Linq.Expressions; using System.Reflection; +using System.Text; using Microsoft.UI.Xaml; @@ -13,12 +14,18 @@ namespace ReactiveUI.Binding.Maui; -/// -/// Creates an observable for a property if available that is based on a WinUI DependencyProperty. -/// +/// Creates an observable for a property if available that is based on a WinUI DependencyProperty. [RequiresUnreferencedCode("Uses reflection to find DependencyProperty static fields/properties.")] public class DependencyObjectObservableForProperty : ICreatesObservableForProperty { + /// Message logged when a caller asks for before-change notifications a DependencyProperty cannot provide. + private static readonly CompositeFormat BeforeChangedUnsupportedFormat = CompositeFormat.Parse( + "[ReactiveUI.Binding.Maui] Tried to bind DO {0}.{1}, but DPs can't do beforeChanged. Binding as POCO object"); + + /// Message logged when the requested property is not backed by a DependencyProperty. + private static readonly CompositeFormat DependencyPropertyMissingFormat = CompositeFormat.Parse( + "[ReactiveUI.Binding.Maui] Tried to bind DO {0}.{1}, but DP doesn't exist. Binding as POCO object"); + /// [RequiresUnreferencedCode("Uses reflection to find DependencyProperty.")] public int GetAffinityForObject(Type type, string propertyName, bool beforeChanged) @@ -28,12 +35,7 @@ public int GetAffinityForObject(Type type, string propertyName, bool beforeChang return 0; } - if (GetDependencyPropertyFetcher(type, propertyName) is null) - { - return 0; - } - - return BindingAffinity.WinUiDependencyObject; + return GetDependencyPropertyFetcher(type, propertyName) is null ? 0 : BindingAffinity.WinUiDependencyObject; } /// @@ -59,7 +61,7 @@ public int GetAffinityForObject(Type type, string propertyName, bool beforeChang Debug.WriteLine( string.Format( CultureInfo.InvariantCulture, - "[ReactiveUI.Binding.Maui] Tried to bind DO {0}.{1}, but DPs can't do beforeChanged. Binding as POCO object", + BeforeChangedUnsupportedFormat, type.FullName, propertyName)); @@ -67,13 +69,13 @@ public int GetAffinityForObject(Type type, string propertyName, bool beforeChang return ret.GetNotificationForProperty(sender, expression, propertyName, beforeChanged, suppressWarnings); } - var dpFetcher = GetDependencyPropertyFetcher(type, propertyName); - if (dpFetcher is null) + var dependencyPropertyFetcher = GetDependencyPropertyFetcher(type, propertyName); + if (dependencyPropertyFetcher is null) { Debug.WriteLine( string.Format( CultureInfo.InvariantCulture, - "[ReactiveUI.Binding.Maui] Tried to bind DO {0}.{1}, but DP doesn't exist. Binding as POCO object", + DependencyPropertyMissingFormat, type.FullName, propertyName)); @@ -86,15 +88,15 @@ public int GetAffinityForObject(Type type, string propertyName, bool beforeChang var handler = new DependencyPropertyChangedCallback((_, _) => subj.OnNext(new ObservedChange(sender, expression, default))); - var dependencyProperty = dpFetcher(); + var dependencyProperty = dependencyPropertyFetcher(); var token = depSender.RegisterPropertyChangedCallback(dependencyProperty, handler); - return Disposable.Create(() => depSender.UnregisterPropertyChangedCallback(dependencyProperty, token)); + return Disposable.Create( + (depSender, dependencyProperty, token), + static state => state.depSender.UnregisterPropertyChangedCallback(state.dependencyProperty, state.token)); }); } - /// - /// Walks the type hierarchy to find a static property with the given name. - /// + /// Walks the type hierarchy to find a static property with the given name. /// The type info to search. /// The property name to find. /// The property info if found; otherwise, null. @@ -116,9 +118,7 @@ public int GetAffinityForObject(Type type, string propertyName, bool beforeChang return null; } - /// - /// Walks the type hierarchy to find a static field with the given name. - /// + /// Walks the type hierarchy to find a static field with the given name. /// The type info to search. /// The field name to find. /// The field info if found; otherwise, null. @@ -140,9 +140,7 @@ public int GetAffinityForObject(Type type, string propertyName, bool beforeChang return null; } - /// - /// Gets a function that returns the DependencyProperty for the given property name. - /// + /// Gets a function that returns the DependencyProperty for the given property name. /// The type to search for the DependencyProperty. /// The property name whose DependencyProperty to find. /// A function returning the DependencyProperty, or null if not found. @@ -152,30 +150,20 @@ public int GetAffinityForObject(Type type, string propertyName, bool beforeChang var typeInfo = type.GetTypeInfo(); // Look for the DependencyProperty attached to this property name - var pi = ActuallyGetProperty(typeInfo, propertyName + "Property"); + var pi = ActuallyGetProperty(typeInfo, $"{propertyName}Property"); if (pi is not null) { var value = pi.GetValue(null); - if (value is null) - { - return null; - } - - return () => (DependencyProperty)value; + return value is null ? null : () => (DependencyProperty)value; } - var fi = ActuallyGetField(typeInfo, propertyName + "Property"); + var fi = ActuallyGetField(typeInfo, $"{propertyName}Property"); if (fi is not null) { var value = fi.GetValue(null); - if (value is null) - { - return null; - } - - return () => (DependencyProperty)value; + return value is null ? null : () => (DependencyProperty)value; } return null; diff --git a/src/ReactiveUI.Binding.Maui/MauiBindingModule.cs b/src/ReactiveUI.Binding.Maui/MauiBindingModule.cs index 40d3a29..1e82900 100644 --- a/src/ReactiveUI.Binding.Maui/MauiBindingModule.cs +++ b/src/ReactiveUI.Binding.Maui/MauiBindingModule.cs @@ -6,9 +6,7 @@ namespace ReactiveUI.Binding.Maui; -/// -/// MAUI-specific module that registers platform services with the dependency resolver. -/// +/// MAUI-specific module that registers platform services with the dependency resolver. public sealed class MauiBindingModule : IModule { /// @@ -17,9 +15,9 @@ public void Configure(IMutableDependencyResolver resolver) ArgumentExceptionHelper.ThrowIfNull(resolver); #if WINUI_TARGET - resolver.RegisterLazySingleton(() => new DependencyObjectObservableForProperty()); + resolver.RegisterLazySingleton(static () => new DependencyObjectObservableForProperty()); #endif - resolver.RegisterLazySingleton(() => new BooleanToVisibilityTypeConverter()); - resolver.RegisterLazySingleton(() => new VisibilityToBooleanTypeConverter()); + resolver.RegisterLazySingleton(static () => new BooleanToVisibilityTypeConverter()); + resolver.RegisterLazySingleton(static () => new VisibilityToBooleanTypeConverter()); } } diff --git a/src/ReactiveUI.Binding.Maui/ReactiveUI.Binding.Maui.csproj b/src/ReactiveUI.Binding.Maui/ReactiveUI.Binding.Maui.csproj index b4b80c4..95f7def 100644 --- a/src/ReactiveUI.Binding.Maui/ReactiveUI.Binding.Maui.csproj +++ b/src/ReactiveUI.Binding.Maui/ReactiveUI.Binding.Maui.csproj @@ -19,6 +19,12 @@ $(DefineConstants);WINUI_TARGET + + + + + diff --git a/src/ReactiveUI.Binding.Maui/VisibilityToBooleanTypeConverter.cs b/src/ReactiveUI.Binding.Maui/VisibilityToBooleanTypeConverter.cs index 7b651e6..314b93e 100644 --- a/src/ReactiveUI.Binding.Maui/VisibilityToBooleanTypeConverter.cs +++ b/src/ReactiveUI.Binding.Maui/VisibilityToBooleanTypeConverter.cs @@ -10,9 +10,7 @@ namespace ReactiveUI.Binding.Maui; -/// -/// Converts to . -/// +/// Converts to . /// /// /// The conversion supports a as the conversion hint parameter: diff --git a/src/ReactiveUI.Binding.Reactive/ObserveOnObservable.cs b/src/ReactiveUI.Binding.Reactive/ObserveOnObservable.cs index bbe00e2..88334b2 100644 --- a/src/ReactiveUI.Binding.Reactive/ObserveOnObservable.cs +++ b/src/ReactiveUI.Binding.Reactive/ObserveOnObservable.cs @@ -15,19 +15,13 @@ namespace ReactiveUI.Binding.Reactive; [EditorBrowsable(EditorBrowsableState.Never)] public sealed class ObserveOnObservable : IObservable { - /// - /// The source observable to observe on the specified scheduler. - /// + /// The source observable to observe on the specified scheduler. private readonly IObservable _source; - /// - /// The scheduler to forward notifications on. - /// + /// The scheduler to forward notifications on. private readonly IScheduler _scheduler; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The source observable to observe on the specified scheduler. /// The scheduler to forward notifications on. public ObserveOnObservable(IObservable source, IScheduler scheduler) @@ -49,38 +43,20 @@ public IDisposable Subscribe(IObserver observer) return composite; } - /// - /// Observer that forwards notifications to the downstream observer on the specified scheduler. - /// - private sealed class ObserveOnObserver : IObserver + /// Observer that forwards notifications to the downstream observer on the specified scheduler. + /// The downstream observer. + /// The scheduler to forward notifications on. + /// The composite disposable tracking scheduled work. + private sealed class ObserveOnObserver(IObserver observer, IScheduler scheduler, CompositeDisposable disposable) : IObserver { - /// - /// The downstream observer. - /// - private readonly IObserver _observer; - - /// - /// The scheduler to forward notifications on. - /// - private readonly IScheduler _scheduler; + /// The downstream observer. + private readonly IObserver _observer = observer; - /// - /// The composite disposable tracking scheduled work. - /// - private readonly CompositeDisposable _disposable; + /// The scheduler to forward notifications on. + private readonly IScheduler _scheduler = scheduler; - /// - /// Initializes a new instance of the class. - /// - /// The downstream observer. - /// The scheduler to forward notifications on. - /// The composite disposable tracking scheduled work. - public ObserveOnObserver(IObserver observer, IScheduler scheduler, CompositeDisposable disposable) - { - _observer = observer; - _scheduler = scheduler; - _disposable = disposable; - } + /// The composite disposable tracking scheduled work. + private readonly CompositeDisposable _disposable = disposable; /// public void OnCompleted() diff --git a/src/ReactiveUI.Binding.Reactive/ReactiveSchedulerExtensions.cs b/src/ReactiveUI.Binding.Reactive/ReactiveSchedulerExtensions.cs index 440ce10..1d07cbd 100644 --- a/src/ReactiveUI.Binding.Reactive/ReactiveSchedulerExtensions.cs +++ b/src/ReactiveUI.Binding.Reactive/ReactiveSchedulerExtensions.cs @@ -9,14 +9,6 @@ namespace ReactiveUI.Binding; /// Requires the ReactiveUI.Binding.Reactive package for System.Reactive interop. /// [ExcludeFromCodeCoverage] -[SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "Parameter count comes from compiler-populated CallerInfo params that cannot be bundled; the generator binds to these exact signatures.")] -[SuppressMessage( - "Critical Code Smell", - "S2360:Optional parameters should not be used", - Justification = "The optional parameters are part of the CallerInfo dispatch contract; replacing them with overloads would exceed the parameter-count limit (S107).")] public static class ReactiveSchedulerExtensions { /// @@ -28,529 +20,476 @@ public static class ReactiveSchedulerExtensions private const string NoGeneratedBindingMessage = "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."; -#if NET8_0_OR_GREATER - /// - /// Creates a one-way binding from a source property to a target property with a specified scheduler. - /// + /// Provides BindOneWay extension members for . /// The type of the source object. - /// The type of the target object. - /// The type of the property being bound. /// The source object to observe for property changes. - /// The target object whose property will be updated. - /// An expression that selects the source property to observe. - /// An expression that selects the target property to update. - /// The scheduler to use for the binding. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// A disposable that, when disposed, disconnects the binding. - public static IDisposable BindOneWay( - this TSource source, - TTarget target, - Expression> sourceProperty, - Expression> targetProperty, - IScheduler? scheduler, - [CallerArgumentExpression("sourceProperty")] - string sourcePropertyExpression = "", - [CallerArgumentExpression("targetProperty")] - string targetPropertyExpression = "", - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) + extension(TSource source) where TSource : class - where TTarget : class + { +#if NET8_0_OR_GREATER + /// Creates a one-way binding from a source property to a target property with a specified scheduler. + /// The type of the target object. + /// The type of the property being bound. + /// The target object whose property will be updated. + /// An expression that selects the source property to observe. + /// An expression that selects the target property to update. + /// The scheduler to use for the binding. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// A disposable that, when disposed, disconnects the binding. + public IDisposable BindOneWay( + TTarget target, + Expression> sourceProperty, + Expression> targetProperty, + IScheduler? scheduler, + [CallerArgumentExpression("sourceProperty")] + string sourcePropertyExpression = "", + [CallerArgumentExpression("targetProperty")] + string targetPropertyExpression = "", + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TTarget : class #else - /// - /// Creates a one-way binding from a source property to a target property with a specified scheduler. - /// - /// The type of the source object. - /// The type of the target object. - /// The type of the property being bound. - /// The source object to observe for property changes. - /// The target object whose property will be updated. - /// An expression that selects the source property to observe. - /// An expression that selects the target property to update. - /// The scheduler to use for the binding. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// A disposable that, when disposed, disconnects the binding. - public static IDisposable BindOneWay( - this TSource source, - TTarget target, - Expression> sourceProperty, - Expression> targetProperty, - IScheduler? scheduler, - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSource : class - where TTarget : class + /// Creates a one-way binding from a source property to a target property with a specified scheduler. + /// The type of the target object. + /// The type of the property being bound. + /// The target object whose property will be updated. + /// An expression that selects the source property to observe. + /// An expression that selects the target property to update. + /// The scheduler to use for the binding. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// A disposable that, when disposed, disconnects the binding. + public IDisposable BindOneWay( + TTarget target, + Expression> sourceProperty, + Expression> targetProperty, + IScheduler? scheduler, + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TTarget : class #endif - { - throw new InvalidOperationException(NoGeneratedBindingMessage); - } + { + throw new InvalidOperationException(NoGeneratedBindingMessage); + } #if NET8_0_OR_GREATER - /// - /// Creates a one-way binding from a source property to a target property with a conversion function and a specified scheduler. - /// - /// The type of the source object. - /// The type of the source property. - /// The type of the target object. - /// The type of the target property. - /// The source object to observe for property changes. - /// The target object whose property will be updated. - /// An expression that selects the source property to observe. - /// An expression that selects the target property to update. - /// A function that converts the source property value to the target property type. - /// The scheduler to use for the binding. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// A disposable that, when disposed, disconnects the binding. - public static IDisposable BindOneWay( - this TSource source, - TTarget target, - Expression> sourceProperty, - Expression> targetProperty, - Func conversionFunc, - IScheduler? scheduler, - [CallerArgumentExpression("sourceProperty")] - string sourcePropertyExpression = "", - [CallerArgumentExpression("targetProperty")] - string targetPropertyExpression = "", - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSource : class - where TTarget : class + /// + /// Creates a one-way binding from a source property to a target property with a conversion function and a specified scheduler. + /// + /// The type of the source property. + /// The type of the target object. + /// The type of the target property. + /// The target object whose property will be updated. + /// An expression that selects the source property to observe. + /// An expression that selects the target property to update. + /// A function that converts the source property value to the target property type. + /// The scheduler to use for the binding. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// A disposable that, when disposed, disconnects the binding. + public IDisposable BindOneWay( + TTarget target, + Expression> sourceProperty, + Expression> targetProperty, + Func conversionFunc, + IScheduler? scheduler, + [CallerArgumentExpression("sourceProperty")] + string sourcePropertyExpression = "", + [CallerArgumentExpression("targetProperty")] + string targetPropertyExpression = "", + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TTarget : class #else - /// - /// Creates a one-way binding from a source property to a target property with a conversion function and a specified scheduler. - /// - /// The type of the source object. - /// The type of the source property. - /// The type of the target object. - /// The type of the target property. - /// The source object to observe for property changes. - /// The target object whose property will be updated. - /// An expression that selects the source property to observe. - /// An expression that selects the target property to update. - /// A function that converts the source property value to the target property type. - /// The scheduler to use for the binding. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// A disposable that, when disposed, disconnects the binding. - public static IDisposable BindOneWay( - this TSource source, - TTarget target, - Expression> sourceProperty, - Expression> targetProperty, - Func conversionFunc, - IScheduler? scheduler, - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSource : class - where TTarget : class + /// + /// Creates a one-way binding from a source property to a target property with a conversion function and a specified scheduler. + /// + /// The type of the source property. + /// The type of the target object. + /// The type of the target property. + /// The target object whose property will be updated. + /// An expression that selects the source property to observe. + /// An expression that selects the target property to update. + /// A function that converts the source property value to the target property type. + /// The scheduler to use for the binding. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// A disposable that, when disposed, disconnects the binding. + public IDisposable BindOneWay( + TTarget target, + Expression> sourceProperty, + Expression> targetProperty, + Func conversionFunc, + IScheduler? scheduler, + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TTarget : class #endif - { - throw new InvalidOperationException(NoGeneratedBindingMessage); - } + { + throw new InvalidOperationException(NoGeneratedBindingMessage); + } - /// - /// Creates a one-way binding from a source property to a target property using an explicit . - /// - /// The type of the source object. - /// The type of the source property. - /// The type of the target object. - /// The type of the target property. - /// The source object to observe for property changes. - /// The target object whose property will be updated. - /// An expression that selects the source property to observe. - /// An expression that selects the target property to update. - /// The binding type converter to use for converting between source and target types. - /// An optional hint passed to the converter (e.g., format string). - /// The scheduler to use for the binding. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// A disposable that, when disposed, disconnects the binding. - public static IDisposable BindOneWay( - this TSource source, - TTarget target, - Expression> sourceProperty, - Expression> targetProperty, - IBindingTypeConverter converter, - object? conversionHint = null, - IScheduler? scheduler = null, - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSource : class - where TTarget : class - => throw new InvalidOperationException(NoGeneratedBindingMessage); + /// Creates a one-way binding from a source property to a target property using an explicit . + /// The type of the source property. + /// The type of the target object. + /// The type of the target property. + /// The target object whose property will be updated. + /// An expression that selects the source property to observe. + /// An expression that selects the target property to update. + /// The binding type converter to use for converting between source and target types. + /// An optional hint passed to the converter (e.g., format string). + /// The scheduler to use for the binding. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// A disposable that, when disposed, disconnects the binding. + [SuppressMessage( + "Design", + "SST2309:Optional parameters should be overloads", + Justification = "Part of the CallerInfo dispatch contract; overloads would exceed the parameter limit.")] + public IDisposable BindOneWay( + TTarget target, + Expression> sourceProperty, + Expression> targetProperty, + IBindingTypeConverter converter, + object? conversionHint = null, + IScheduler? scheduler = null, + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TTarget : class => + throw new InvalidOperationException(NoGeneratedBindingMessage); #if NET8_0_OR_GREATER - /// - /// Creates a two-way binding between a source property and a target property with a specified scheduler. - /// - /// The type of the source object. - /// The type of the target object. - /// The type of the property being bound. - /// The source object to observe for property changes. - /// The target object whose property will be updated. - /// An expression that selects the source property to observe. - /// An expression that selects the target property to update. - /// The scheduler to use for the binding. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// A disposable that, when disposed, disconnects the binding. - public static IDisposable BindTwoWay( - this TSource source, - TTarget target, - Expression> sourceProperty, - Expression> targetProperty, - IScheduler? scheduler, - [CallerArgumentExpression("sourceProperty")] - string sourcePropertyExpression = "", - [CallerArgumentExpression("targetProperty")] - string targetPropertyExpression = "", - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSource : class - where TTarget : class + /// Creates a two-way binding between a source property and a target property with a specified scheduler. + /// The type of the target object. + /// The type of the property being bound. + /// The target object whose property will be updated. + /// An expression that selects the source property to observe. + /// An expression that selects the target property to update. + /// The scheduler to use for the binding. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// A disposable that, when disposed, disconnects the binding. + public IDisposable BindTwoWay( + TTarget target, + Expression> sourceProperty, + Expression> targetProperty, + IScheduler? scheduler, + [CallerArgumentExpression("sourceProperty")] + string sourcePropertyExpression = "", + [CallerArgumentExpression("targetProperty")] + string targetPropertyExpression = "", + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TTarget : class #else - /// - /// Creates a two-way binding between a source property and a target property with a specified scheduler. - /// - /// The type of the source object. - /// The type of the target object. - /// The type of the property being bound. - /// The source object to observe for property changes. - /// The target object whose property will be updated. - /// An expression that selects the source property to observe. - /// An expression that selects the target property to update. - /// The scheduler to use for the binding. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// A disposable that, when disposed, disconnects the binding. - public static IDisposable BindTwoWay( - this TSource source, - TTarget target, - Expression> sourceProperty, - Expression> targetProperty, - IScheduler? scheduler, - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSource : class - where TTarget : class + /// Creates a two-way binding between a source property and a target property with a specified scheduler. + /// The type of the target object. + /// The type of the property being bound. + /// The target object whose property will be updated. + /// An expression that selects the source property to observe. + /// An expression that selects the target property to update. + /// The scheduler to use for the binding. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// A disposable that, when disposed, disconnects the binding. + public IDisposable BindTwoWay( + TTarget target, + Expression> sourceProperty, + Expression> targetProperty, + IScheduler? scheduler, + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TTarget : class #endif - { - throw new InvalidOperationException(NoGeneratedBindingMessage); - } + { + throw new InvalidOperationException(NoGeneratedBindingMessage); + } #if NET8_0_OR_GREATER - /// - /// Creates a two-way binding between a source property and a target property with conversion functions and a specified scheduler. - /// - /// The type of the source object. - /// The type of the source property. - /// The type of the target object. - /// The type of the target property. - /// The source object to observe for property changes. - /// The target object whose property will be updated. - /// An expression that selects the source property to observe. - /// An expression that selects the target property to update. - /// A function that converts the source property value to the target property type. - /// A function that converts the target property value back to the source property type. - /// The scheduler to use for the binding. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// A disposable that, when disposed, disconnects the binding. - public static IDisposable BindTwoWay( - this TSource source, - TTarget target, - Expression> sourceProperty, - Expression> targetProperty, - Func sourceToTargetConv, - Func targetToSourceConv, - IScheduler? scheduler, - [CallerArgumentExpression("sourceProperty")] - string sourcePropertyExpression = "", - [CallerArgumentExpression("targetProperty")] - string targetPropertyExpression = "", - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSource : class - where TTarget : class + /// + /// Creates a two-way binding between a source property and a target property with conversion functions and a specified scheduler. + /// + /// The type of the source property. + /// The type of the target object. + /// The type of the target property. + /// The target object whose property will be updated. + /// An expression that selects the source property to observe. + /// An expression that selects the target property to update. + /// A function that converts the source property value to the target property type. + /// A function that converts the target property value back to the source property type. + /// The scheduler to use for the binding. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// A disposable that, when disposed, disconnects the binding. + public IDisposable BindTwoWay( + TTarget target, + Expression> sourceProperty, + Expression> targetProperty, + Func sourceToTargetConv, + Func targetToSourceConv, + IScheduler? scheduler, + [CallerArgumentExpression("sourceProperty")] + string sourcePropertyExpression = "", + [CallerArgumentExpression("targetProperty")] + string targetPropertyExpression = "", + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TTarget : class #else - /// - /// Creates a two-way binding between a source property and a target property with conversion functions and a specified scheduler. - /// - /// The type of the source object. - /// The type of the source property. - /// The type of the target object. - /// The type of the target property. - /// The source object to observe for property changes. - /// The target object whose property will be updated. - /// An expression that selects the source property to observe. - /// An expression that selects the target property to update. - /// A function that converts the source property value to the target property type. - /// A function that converts the target property value back to the source property type. - /// The scheduler to use for the binding. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// A disposable that, when disposed, disconnects the binding. - public static IDisposable BindTwoWay( - this TSource source, - TTarget target, - Expression> sourceProperty, - Expression> targetProperty, - Func sourceToTargetConv, - Func targetToSourceConv, - IScheduler? scheduler, - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSource : class - where TTarget : class + /// + /// Creates a two-way binding between a source property and a target property with conversion functions and a specified scheduler. + /// + /// The type of the source property. + /// The type of the target object. + /// The type of the target property. + /// The target object whose property will be updated. + /// An expression that selects the source property to observe. + /// An expression that selects the target property to update. + /// A function that converts the source property value to the target property type. + /// A function that converts the target property value back to the source property type. + /// The scheduler to use for the binding. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// A disposable that, when disposed, disconnects the binding. + public IDisposable BindTwoWay( + TTarget target, + Expression> sourceProperty, + Expression> targetProperty, + Func sourceToTargetConv, + Func targetToSourceConv, + IScheduler? scheduler, + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TTarget : class #endif - { - throw new InvalidOperationException(NoGeneratedBindingMessage); - } + { + throw new InvalidOperationException(NoGeneratedBindingMessage); + } - /// - /// Creates a two-way binding between a source property and a target property using explicit instances. - /// - /// The type of the source object. - /// The type of the source property. - /// The type of the target object. - /// The type of the target property. - /// The source object to observe for property changes. - /// The target object whose property will be updated. - /// An expression that selects the source property to observe. - /// An expression that selects the target property to update. - /// The converter for source-to-target conversion. - /// The converter for target-to-source conversion. - /// An optional hint passed to the converters (e.g., format string). - /// The scheduler to use for the binding. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// A disposable that, when disposed, disconnects the binding. - public static IDisposable BindTwoWay( - this TSource source, - TTarget target, - Expression> sourceProperty, - Expression> targetProperty, - IBindingTypeConverter sourceToTargetConverter, - IBindingTypeConverter targetToSourceConverter, - object? conversionHint = null, - IScheduler? scheduler = null, - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSource : class - where TTarget : class - => throw new InvalidOperationException(NoGeneratedBindingMessage); + /// Creates a two-way binding between a source property and a target property using explicit instances. + /// The type of the source property. + /// The type of the target object. + /// The type of the target property. + /// The target object whose property will be updated. + /// An expression that selects the source property to observe. + /// An expression that selects the target property to update. + /// The converter for source-to-target conversion. + /// The converter for target-to-source conversion. + /// An optional hint passed to the converters (e.g., format string). + /// The scheduler to use for the binding. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// A disposable that, when disposed, disconnects the binding. + [SuppressMessage( + "Design", + "SST2309:Optional parameters should be overloads", + Justification = "Part of the CallerInfo dispatch contract; overloads would exceed the parameter limit.")] + public IDisposable BindTwoWay( + TTarget target, + Expression> sourceProperty, + Expression> targetProperty, + IBindingTypeConverter sourceToTargetConverter, + IBindingTypeConverter targetToSourceConverter, + object? conversionHint = null, + IScheduler? scheduler = null, + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TTarget : class => + throw new InvalidOperationException(NoGeneratedBindingMessage); -#if NET8_0_OR_GREATER - /// - /// Creates a one-way binding from a view model property to a view property with a specified selector and scheduler. - /// - /// The type of the view model. + } + + /// Provides OneWayBind extension members for . /// The type of the view. - /// The type of the view model property. - /// The type of the view property. /// The view to bind to. - /// The view model to observe. - /// An expression that selects the view model property to observe. - /// An expression that selects the view property to update. - /// A function that converts the view model property value to the view property type. - /// The scheduler to use for the binding. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// A reactive binding that can be disposed to disconnect the binding. - public static IReactiveBinding OneWayBind( - this TView view, - TViewModel viewModel, - Expression> vmProperty, - Expression> viewProperty, - Func selector, - IScheduler? scheduler, - [CallerArgumentExpression("vmProperty")] - string vmPropertyExpression = "", - [CallerArgumentExpression("viewProperty")] - string viewPropertyExpression = "", - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TViewModel : class + extension(TView view) where TView : class, IViewFor + { +#if NET8_0_OR_GREATER + /// Creates a one-way binding from a view model property to a view property with a specified selector and scheduler. + /// The type of the view model. + /// The type of the view model property. + /// The type of the view property. + /// The view model to observe. + /// An expression that selects the view model property to observe. + /// An expression that selects the view property to update. + /// A function that converts the view model property value to the view property type. + /// The scheduler to use for the binding. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// A reactive binding that can be disposed to disconnect the binding. + public IReactiveBinding OneWayBind( + TViewModel viewModel, + Expression> viewModelProperty, + Expression> viewProperty, + Func selector, + IScheduler? scheduler, + [CallerArgumentExpression("viewModelProperty")] + string viewModelPropertyExpression = "", + [CallerArgumentExpression("viewProperty")] + string viewPropertyExpression = "", + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TViewModel : class #else - /// - /// Creates a one-way binding from a view model property to a view property with a specified selector and scheduler. - /// - /// The type of the view model. - /// The type of the view. - /// The type of the view model property. - /// The type of the view property. - /// The view to bind to. - /// The view model to observe. - /// An expression that selects the view model property to observe. - /// An expression that selects the view property to update. - /// A function that converts the view model property value to the view property type. - /// The scheduler to use for the binding. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// A reactive binding that can be disposed to disconnect the binding. - public static IReactiveBinding OneWayBind( - this TView view, - TViewModel viewModel, - Expression> vmProperty, - Expression> viewProperty, - Func selector, - IScheduler? scheduler, - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TViewModel : class - where TView : class, IViewFor + /// Creates a one-way binding from a view model property to a view property with a specified selector and scheduler. + /// The type of the view model. + /// The type of the view model property. + /// The type of the view property. + /// The view model to observe. + /// An expression that selects the view model property to observe. + /// An expression that selects the view property to update. + /// A function that converts the view model property value to the view property type. + /// The scheduler to use for the binding. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// A reactive binding that can be disposed to disconnect the binding. + public IReactiveBinding OneWayBind( + TViewModel viewModel, + Expression> viewModelProperty, + Expression> viewProperty, + Func selector, + IScheduler? scheduler, + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TViewModel : class #endif - { - throw new InvalidOperationException(NoGeneratedBindingMessage); - } + { + throw new InvalidOperationException(NoGeneratedBindingMessage); + } - /// - /// Creates a one-way binding from a view model property to a view property using an explicit . - /// - /// The type of the view model. - /// The type of the view. - /// The type of the view model property. - /// The type of the view property. - /// The view to bind to. - /// The view model to observe. - /// An expression that selects the view model property to observe. - /// An expression that selects the view property to update. - /// The binding type converter to use for converting between source and target types. - /// An optional hint passed to the converter (e.g., format string). - /// The scheduler to use for the binding. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// A reactive binding that can be disposed to disconnect the binding. - public static IReactiveBinding OneWayBind( - this TView view, - TViewModel viewModel, - Expression> vmProperty, - Expression> viewProperty, - IBindingTypeConverter converter, - object? conversionHint = null, - IScheduler? scheduler = null, - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TViewModel : class - where TView : class, IViewFor - => throw new InvalidOperationException(NoGeneratedBindingMessage); + /// Creates a one-way binding from a view model property to a view property using an explicit . + /// The type of the view model. + /// The type of the view model property. + /// The type of the view property. + /// The view model to observe. + /// An expression that selects the view model property to observe. + /// An expression that selects the view property to update. + /// The binding type converter to use for converting between source and target types. + /// An optional hint passed to the converter (e.g., format string). + /// The scheduler to use for the binding. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// A reactive binding that can be disposed to disconnect the binding. + [SuppressMessage( + "Design", + "SST2309:Optional parameters should be overloads", + Justification = "Part of the CallerInfo dispatch contract; overloads would exceed the parameter limit.")] + public IReactiveBinding OneWayBind( + TViewModel viewModel, + Expression> viewModelProperty, + Expression> viewProperty, + IBindingTypeConverter converter, + object? conversionHint = null, + IScheduler? scheduler = null, + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TViewModel : class => + throw new InvalidOperationException(NoGeneratedBindingMessage); #if NET8_0_OR_GREATER - /// - /// Creates a two-way binding between a view model property and a view property with conversion functions and a specified scheduler. - /// - /// The type of the view model. - /// The type of the view. - /// The type of the view model property. - /// The type of the view property. - /// The view to bind to. - /// The view model to observe. - /// An expression that selects the view model property to observe. - /// An expression that selects the view property to update. - /// A function that converts the view model property value to the view property type. - /// A function that converts the view property value back to the view model property type. - /// The scheduler to use for the binding. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// A reactive binding that can be disposed to disconnect the binding. - public static IReactiveBinding Bind( - this TView view, - TViewModel viewModel, - Expression> vmProperty, - Expression> viewProperty, - Func vmToViewConverter, - Func viewToVmConverter, - IScheduler? scheduler, - [CallerArgumentExpression("vmProperty")] - string vmPropertyExpression = "", - [CallerArgumentExpression("viewProperty")] - string viewPropertyExpression = "", - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TViewModel : class - where TView : class, IViewFor + /// + /// Creates a two-way binding between a view model property and a view property with conversion functions and a specified scheduler. + /// + /// The type of the view model. + /// The type of the view model property. + /// The type of the view property. + /// The view model to observe. + /// An expression that selects the view model property to observe. + /// An expression that selects the view property to update. + /// A function that converts the view model property value to the view property type. + /// A function that converts the view property value back to the view model property type. + /// The scheduler to use for the binding. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// A reactive binding that can be disposed to disconnect the binding. + public IReactiveBinding Bind( + TViewModel viewModel, + Expression> viewModelProperty, + Expression> viewProperty, + Func viewModelToViewConverter, + Func viewToViewModelConverter, + IScheduler? scheduler, + [CallerArgumentExpression("viewModelProperty")] + string viewModelPropertyExpression = "", + [CallerArgumentExpression("viewProperty")] + string viewPropertyExpression = "", + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TViewModel : class #else - /// - /// Creates a two-way binding between a view model property and a view property with conversion functions and a specified scheduler. - /// - /// The type of the view model. - /// The type of the view. - /// The type of the view model property. - /// The type of the view property. - /// The view to bind to. - /// The view model to observe. - /// An expression that selects the view model property to observe. - /// An expression that selects the view property to update. - /// A function that converts the view model property value to the view property type. - /// A function that converts the view property value back to the view model property type. - /// The scheduler to use for the binding. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// A reactive binding that can be disposed to disconnect the binding. - public static IReactiveBinding Bind( - this TView view, - TViewModel viewModel, - Expression> vmProperty, - Expression> viewProperty, - Func vmToViewConverter, - Func viewToVmConverter, - IScheduler? scheduler, - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TViewModel : class - where TView : class, IViewFor + /// + /// Creates a two-way binding between a view model property and a view property with conversion functions and a specified scheduler. + /// + /// The type of the view model. + /// The type of the view model property. + /// The type of the view property. + /// The view model to observe. + /// An expression that selects the view model property to observe. + /// An expression that selects the view property to update. + /// A function that converts the view model property value to the view property type. + /// A function that converts the view property value back to the view model property type. + /// The scheduler to use for the binding. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// A reactive binding that can be disposed to disconnect the binding. + public IReactiveBinding Bind( + TViewModel viewModel, + Expression> viewModelProperty, + Expression> viewProperty, + Func viewModelToViewConverter, + Func viewToViewModelConverter, + IScheduler? scheduler, + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TViewModel : class #endif - { - throw new InvalidOperationException(NoGeneratedBindingMessage); - } + { + throw new InvalidOperationException(NoGeneratedBindingMessage); + } - /// - /// Creates a two-way binding between a view model property and a view property using explicit instances. - /// - /// The type of the view model. - /// The type of the view. - /// The type of the view model property. - /// The type of the view property. - /// The view to bind to. - /// The view model to observe. - /// An expression that selects the view model property to observe. - /// An expression that selects the view property to update. - /// The converter for view model-to-view conversion. - /// The converter for view-to-view model conversion. - /// An optional hint passed to the converters (e.g., format string). - /// The scheduler to use for the binding. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// A reactive binding that can be disposed to disconnect the binding. - public static IReactiveBinding Bind( - this TView view, - TViewModel viewModel, - Expression> vmProperty, - Expression> viewProperty, - IBindingTypeConverter vmToViewConverter, - IBindingTypeConverter viewToVmConverter, - object? conversionHint = null, - IScheduler? scheduler = null, - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TViewModel : class - where TView : class, IViewFor - => throw new InvalidOperationException(NoGeneratedBindingMessage); + /// Creates a two-way binding between a view model property and a view property using explicit instances. + /// The type of the view model. + /// The type of the view model property. + /// The type of the view property. + /// The view model to observe. + /// An expression that selects the view model property to observe. + /// An expression that selects the view property to update. + /// The converter for view model-to-view conversion. + /// The converter for view-to-view model conversion. + /// An optional hint passed to the converters (e.g., format string). + /// The scheduler to use for the binding. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// A reactive binding that can be disposed to disconnect the binding. + [SuppressMessage( + "Design", + "SST2309:Optional parameters should be overloads", + Justification = "Part of the CallerInfo dispatch contract; overloads would exceed the parameter limit.")] + public IReactiveBinding Bind( + TViewModel viewModel, + Expression> viewModelProperty, + Expression> viewProperty, + IBindingTypeConverter viewModelToViewConverter, + IBindingTypeConverter viewToViewModelConverter, + object? conversionHint = null, + IScheduler? scheduler = null, + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TViewModel : class => + throw new InvalidOperationException(NoGeneratedBindingMessage); + } } diff --git a/src/ReactiveUI.Binding.SourceGenerators/BindingGenerator.cs b/src/ReactiveUI.Binding.SourceGenerators/BindingGenerator.cs index 20828ba..8439f6d 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/BindingGenerator.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/BindingGenerator.cs @@ -25,57 +25,9 @@ public class BindingGenerator : IIncrementalGenerator /// public void Initialize(IncrementalGeneratorInitializationContext context) { - // Emit the [ExcludeFromCodeCoverage] attribute on the partial class once, - // so individual dispatch files don't duplicate it. - context.RegisterPostInitializationOutput(static ctx => - { - // Post-initialization output runs before analyzer config options are available, so this trivial - // (empty) partial class always carries the generated-file markers; an empty class produces no - // diagnostics worth surfacing even when ReactiveUIBindingEmitGeneratedCodeMarkers is disabled. - const string source = """ - // - #pragma warning disable - namespace ReactiveUI.Binding - { - [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - internal static partial class __ReactiveUIGeneratedBindings - { - } - } - """; - ctx.AddSource("GeneratedBindingsAttributes.g.cs", source); - }); - - // Snapshot the consumer's relevant C# language capabilities once, flowed through every invocation - // pipeline. CallerArgumentExpression (C# 10+ AND attribute available) selects expression-text dispatch - // over file/line dispatch; nullable reference types (C# 8+) makes generated files emit '#nullable enable'. - var languageFeatures = context.ParseOptionsProvider - .Combine(context.CompilationProvider) - .Combine(context.AnalyzerConfigOptionsProvider) - .Select(static (data, _) => - { - var parseOptions = data.Left.Left; - var compilation = data.Left.Right; - var configOptions = data.Right; - - var languageVersion = (parseOptions as CSharpParseOptions)?.LanguageVersion ?? LanguageVersion.Default; - var supportsCallerArgExpr = languageVersion >= LanguageVersion.CSharp10 && - compilation.GetTypeByMetadataName( - Constants.CallerArgumentExpressionAttributeMetadataName) is not null; - - // Generated-file markers (// + #pragma warning disable) are emitted by default - // (the shipping convention); consumers opt out with ReactiveUIBindingEmitGeneratedCodeMarkers=false - // to surface analyzer diagnostics in the generated code. Absent property => default (markers on). - var emitGeneratedCodeMarkers = !(configOptions.GlobalOptions.TryGetValue( - "build_property.ReactiveUIBindingEmitGeneratedCodeMarkers", - out var markersValue) - && string.Equals(markersValue, "false", System.StringComparison.OrdinalIgnoreCase)); + RegisterSharedAttributeOutput(in context); - return new LanguageFeatures( - supportsCallerArgExpr, - languageVersion >= LanguageVersion.CSharp8, - emitGeneratedCodeMarkers); - }); + var languageFeatures = SelectLanguageFeatures(in context); // Pipeline A: Shared type detection // One pass: sets flags for IRO, INPC, WpfDP, WinUIDP, KVO, etc. @@ -93,12 +45,7 @@ internal static partial class __ReactiveUIGeneratedBindings .Select(static (classInfo, _) => { var plugin = ObservationPluginRegistry.GetBestPlugin(classInfo); - if (plugin is null) - { - return null; - } - - return new ObservableTypeInfo( + return plugin is null ? null : new ObservableTypeInfo( classInfo.FullyQualifiedName, classInfo.MetadataName, plugin.ObservationKind, @@ -134,4 +81,64 @@ internal static partial class __ReactiveUIGeneratedBindings BindCommandInvocationGenerator.Register(context, allClasses, languageFeatures); BindToInvocationGenerator.Register(context, allClasses, languageFeatures); } + + /// Emits the [ExcludeFromCodeCoverage] partial class once, so dispatch files need not repeat it. + /// The generator initialization context. + private static void RegisterSharedAttributeOutput(in IncrementalGeneratorInitializationContext context) => + context.RegisterPostInitializationOutput(static ctx => + { + // Post-initialization output runs before analyzer config options are available, so this trivial + // (empty) partial class always carries the generated-file markers; an empty class produces no + // diagnostics worth surfacing even when ReactiveUIBindingEmitGeneratedCodeMarkers is disabled. + const string source = """ + // + #pragma warning disable + namespace ReactiveUI.Binding + { + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + internal static partial class __ReactiveUIGeneratedBindings + { + } + } + """; + ctx.AddSource("GeneratedBindingsAttributes.g.cs", source); + }); + + /// + /// Snapshots the consumer's relevant C# language capabilities once, to flow through every + /// invocation pipeline. CallerArgumentExpression (C# 10+ and the attribute being available) + /// selects expression-text dispatch over file and line dispatch; nullable reference types + /// (C# 8+) makes the generated files emit #nullable enable. + /// + /// The generator initialization context. + /// A provider yielding the consumer's language-feature snapshot. + private static IncrementalValueProvider SelectLanguageFeatures( + in IncrementalGeneratorInitializationContext context) => + context.ParseOptionsProvider + .Combine(context.CompilationProvider) + .Combine(context.AnalyzerConfigOptionsProvider) + .Select(static (data, _) => + { + var parseOptions = data.Left.Left; + var compilation = data.Left.Right; + var configOptions = data.Right; + + var languageVersion = (parseOptions as CSharpParseOptions)?.LanguageVersion ?? LanguageVersion.Default; + var supportsCallerArgExpr = languageVersion >= LanguageVersion.CSharp10 + && compilation.GetTypeByMetadataName( + Constants.CallerArgumentExpressionAttributeMetadataName) is not null; + + // Generated-file markers (// + #pragma warning disable) are emitted by default + // (the shipping convention); consumers opt out with ReactiveUIBindingEmitGeneratedCodeMarkers=false + // to surface analyzer diagnostics in the generated code. Absent property => default (markers on). + var emitGeneratedCodeMarkers = !(configOptions.GlobalOptions.TryGetValue( + "build_property.ReactiveUIBindingEmitGeneratedCodeMarkers", + out var markersValue) + && string.Equals(markersValue, "false", System.StringComparison.OrdinalIgnoreCase)); + + return new LanguageFeatures( + supportsCallerArgExpr, + languageVersion >= LanguageVersion.CSharp8, + emitGeneratedCodeMarkers); + }); } diff --git a/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/BindCodeGenerator.cs b/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/BindCodeGenerator.cs index 115438f..1957fa9 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/BindCodeGenerator.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/BindCodeGenerator.cs @@ -14,9 +14,13 @@ namespace ReactiveUI.Binding.SourceGenerators.CodeGeneration; /// internal static class BindCodeGenerator { - /// - /// Generates concrete typed overloads and binding methods for Bind invocations. - /// + /// Name of the generated local holding the view model side observable. + private const string ViewModelObservableName = "vmObs"; + + /// Name of the generated local holding the view side observable. + private const string ViewObservableName = "viewObs"; + + /// Generates concrete typed overloads and binding methods for Bind invocations. /// All detected Bind invocations. /// All detected class binding info. /// The consumer compilation's C# language-feature snapshot (dispatch strategy and nullable support). @@ -31,10 +35,10 @@ internal static class BindCodeGenerator return null; } - var sb = new StringBuilder(invocations.Length * 1_024); + var sb = new StringBuilder(invocations.Length * CodeGeneratorHelpers.PerInvocationBufferCapacity); var supportsCallerArgExpr = features.SupportsCallerArgExpr; CodeGeneratorHelpers.AppendExtensionClassHeader(sb, features); - sb.AppendLine(); + _ = sb.AppendLine(); var groups = GroupByTypeSignature(invocations); @@ -43,7 +47,7 @@ internal static class BindCodeGenerator var group = groups[g]; GenerateConcreteOverload(sb, group, supportsCallerArgExpr, features.SupportsNullable); - sb.AppendLine(); + _ = sb.AppendLine(); for (var i = 0; i < group.Invocations.Length; i++) { @@ -54,31 +58,29 @@ internal static class BindCodeGenerator inv.SourceTypeFullName, inv.CallerFilePath, inv.CallerLineNumber, - inv.SourceExpressionText + "|" + inv.TargetExpressionText); + $"{inv.SourceExpressionText}|{inv.TargetExpressionText}"); GenerateBindMethod(sb, inv, sourceClassInfo, targetClassInfo, suffix, features.SupportsNullable); } } CodeGeneratorHelpers.AppendExtensionClassFooter(sb); - sb.AppendLine(); + _ = sb.AppendLine(); return sb.ToString(); } - /// - /// Groups Bind invocations by their type signature for overload generation. - /// + /// Groups Bind invocations by their type signature for overload generation. /// The Bind invocations to group. /// A list of grouped invocations sharing the same type signature. internal static List GroupByTypeSignature(ImmutableArray invocations) { var groupMap = new Dictionary>(invocations.Length); - var keySb = new StringBuilder(128); + var keySb = new StringBuilder(CodeGeneratorHelpers.FragmentBufferCapacity); for (var i = 0; i < invocations.Length; i++) { var inv = invocations[i]; - keySb.Clear() + _ = keySb.Clear() .Append(inv.SourceTypeFullName).Append('|') .Append(inv.TargetTypeFullName).Append('|') .Append(inv.SourcePropertyTypeFullName).Append('|') @@ -114,9 +116,7 @@ internal static List GroupByTypeSignature(ImmutableArray - /// Generates the concrete typed overload using the appropriate dispatch strategy. - /// + /// Generates the concrete typed overload using the appropriate dispatch strategy. /// The string builder to append to. /// The binding type group. /// Whether CallerArgumentExpression is available. @@ -137,9 +137,7 @@ internal static void GenerateConcreteOverload( } } - /// - /// Generates the CallerArgumentExpression-based overload for Bind dispatch. - /// + /// Generates the CallerArgumentExpression-based overload for Bind dispatch. /// The string builder to append to. /// The binding type group. /// Whether the target supports nullable reference types (C# 8+). @@ -152,7 +150,7 @@ internal static void GenerateCallerArgExprOverload( var targetPropType = CodeGeneratorHelpers.NullableSelectorLeafType(group.Invocations[0].TargetPropertyPath, supportsNullable); var returnType = FormatReturnType(group, supportsNullable); - sb.AppendLine($""" + _ = sb.AppendLine($""" /// /// Concrete typed overload for Bind from {group.SourceTypeFullName} to {group.TargetTypeFullName}. /// Uses CallerArgumentExpression for dispatch. @@ -160,14 +158,14 @@ internal static void GenerateCallerArgExprOverload( public static {returnType} Bind( this {group.TargetTypeFullName} view, {group.SourceTypeFullName} viewModel, - global::System.Linq.Expressions.Expression> vmProperty, + global::System.Linq.Expressions.Expression> viewModelProperty, global::System.Linq.Expressions.Expression> viewProperty, """); AppendExtraParameters(sb, group); - sb.AppendLine(""" - [global::System.Runtime.CompilerServices.CallerArgumentExpression("vmProperty")] string vmPropertyExpression = "", + _ = sb.AppendLine(""" + [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewModelProperty")] string viewModelPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewProperty")] string viewPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) @@ -184,10 +182,10 @@ internal static void GenerateCallerArgExprOverload( inv.SourceTypeFullName, inv.CallerFilePath, inv.CallerLineNumber, - inv.SourceExpressionText + "|" + inv.TargetExpressionText); + $"{inv.SourceExpressionText}|{inv.TargetExpressionText}"); - sb.AppendLine($$""" - {{condition}} (vmPropertyExpression == "{{escapedSourceExpr}}" + _ = sb.AppendLine($$""" + {{condition}} (viewModelPropertyExpression == "{{escapedSourceExpr}}" && viewPropertyExpression == "{{escapedTargetExpr}}") { return __Bind_{{methodSuffix}}(viewModel, view{{FormatExtraArgs(group)}}); @@ -195,16 +193,14 @@ internal static void GenerateCallerArgExprOverload( """); } - sb.AppendLine(""" + _ = sb.AppendLine(""" throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } """); } - /// - /// Generates the CallerFilePath-based overload for Bind dispatch. - /// + /// Generates the CallerFilePath-based overload for Bind dispatch. /// The string builder to append to. /// The binding type group. /// Whether the target supports nullable reference types (C# 8+). @@ -217,7 +213,7 @@ internal static void GenerateCallerFilePathOverload( var targetPropType = CodeGeneratorHelpers.NullableSelectorLeafType(group.Invocations[0].TargetPropertyPath, supportsNullable); var returnType = FormatReturnType(group, supportsNullable); - sb.AppendLine($""" + _ = sb.AppendLine($""" /// /// Concrete typed overload for Bind from {group.SourceTypeFullName} to {group.TargetTypeFullName}. /// Uses CallerFilePath + CallerLineNumber for dispatch. @@ -225,13 +221,13 @@ internal static void GenerateCallerFilePathOverload( public static {returnType} Bind( this {group.TargetTypeFullName} view, {group.SourceTypeFullName} viewModel, - global::System.Linq.Expressions.Expression> vmProperty, + global::System.Linq.Expressions.Expression> viewModelProperty, global::System.Linq.Expressions.Expression> viewProperty, """); AppendExtraParameters(sb, group); - sb.AppendLine(""" + _ = sb.AppendLine(""" [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { @@ -246,9 +242,9 @@ internal static void GenerateCallerFilePathOverload( inv.SourceTypeFullName, inv.CallerFilePath, inv.CallerLineNumber, - inv.SourceExpressionText + "|" + inv.TargetExpressionText); + $"{inv.SourceExpressionText}|{inv.TargetExpressionText}"); - sb.AppendLine($$""" + _ = sb.AppendLine($$""" {{condition}} (callerLineNumber == {{inv.CallerLineNumber}} && callerFilePath.EndsWith("{{CodeGeneratorHelpers.EscapeString(suffix)}}", global::System.StringComparison.OrdinalIgnoreCase)) { @@ -257,16 +253,14 @@ internal static void GenerateCallerFilePathOverload( """); } - sb.AppendLine(""" + _ = sb.AppendLine(""" throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } """); } - /// - /// Generates a private Bind method for a specific invocation. - /// + /// Generates a private Bind method for a specific invocation. /// The string builder to append to. /// The binding invocation info. /// The source type class binding info. @@ -282,8 +276,8 @@ internal static void GenerateBindMethod( bool supportsNullable) { var viewPropertyAccess = CodeGeneratorHelpers.BuildPropertySetterChain("view", inv.TargetPropertyPath); - var vmSetAccess = CodeGeneratorHelpers.BuildPropertySetterChain("viewModel", inv.SourcePropertyPath); - var vmPathComment = CodeGeneratorHelpers.BuildPropertyPathString(inv.SourcePropertyPath); + var viewModelSetAccess = CodeGeneratorHelpers.BuildPropertySetterChain("viewModel", inv.SourcePropertyPath); + var viewModelPathComment = CodeGeneratorHelpers.BuildPropertyPathString(inv.SourcePropertyPath); var viewPathComment = CodeGeneratorHelpers.BuildPropertyPathString(inv.TargetPropertyPath); var extraParams = FormatExtraMethodParams(inv); @@ -291,10 +285,10 @@ internal static void GenerateBindMethod( var schedulerComment = inv.HasScheduler ? " (with scheduler)" : string.Empty; var returnType = FormatMethodReturnType(inv, supportsNullable); - sb.AppendLine($$""" + _ = sb.AppendLine($$""" private static {{returnType}} __Bind_{{suffix}}({{inv.SourceTypeFullName}} viewModel, {{inv.TargetTypeFullName}} view{{extraParams}}) { - // Bind: {{vmPathComment}} <-> {{viewPathComment}}{{conversionComment}}{{schedulerComment}} + // Bind: {{viewModelPathComment}} <-> {{viewPathComment}}{{conversionComment}}{{schedulerComment}} """); // Emit inline observation code instead of delegating to WhenChanged dispatch @@ -304,7 +298,7 @@ internal static void GenerateBindMethod( inv.SourcePropertyPath, inv.SourcePropertyTypeFullName, sourceClassInfo, - "vmObs"); + ViewModelObservableName); ObservationCodeGenerator.EmitInlineObservation( sb, @@ -312,55 +306,30 @@ internal static void GenerateBindMethod( inv.TargetPropertyPath, inv.TargetPropertyTypeFullName, targetClassInfo, - "viewObs"); + ViewObservableName); if (inv.HasConversion || inv.HasScheduler) { - var vmVar = "vmObs"; - var viewVar = "viewObs"; - - if (inv.HasConversion) - { - var vmNext = inv.HasScheduler ? "__vmSelected" : "vmBind"; - var viewNext = inv.HasScheduler ? "__viewSelected" : "viewBind"; - sb.AppendLine($""" - var {vmNext} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({vmVar}, vmToViewConverter); - var {viewNext} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({viewVar}, viewToVmConverter); - """); - vmVar = vmNext; - viewVar = viewNext; - } - - if (inv.HasScheduler) - { - sb.AppendLine($""" - var vmBind = new global::ReactiveUI.Binding.Reactive.ObserveOnObservable<{inv.TargetPropertyTypeFullName}>({vmVar}, scheduler); - var viewBind = new global::ReactiveUI.Binding.Reactive.ObserveOnObservable<{inv.SourcePropertyTypeFullName}>({viewVar}, scheduler); - """); - vmVar = "vmBind"; - viewVar = "viewBind"; - } + var (viewModelVar, viewVar) = EmitConversionAndSchedulerStages(sb, inv); - EmitTwoWaySubscription(sb, inv, vmVar, viewVar, viewPropertyAccess, vmSetAccess, supportsNullable); + EmitTwoWaySubscription(sb, inv, viewModelVar, viewVar, viewPropertyAccess, viewModelSetAccess, supportsNullable); } else { - EmitTwoWaySubscription(sb, inv, "vmObs", "viewObs", viewPropertyAccess, vmSetAccess, supportsNullable); + EmitTwoWaySubscription(sb, inv, ViewModelObservableName, ViewObservableName, viewPropertyAccess, viewModelSetAccess, supportsNullable); } } - /// - /// Appends extra parameters (converters, scheduler) to the concrete overload signature. - /// + /// Appends extra parameters (converters, scheduler) to the concrete overload signature. /// The string builder to append to. /// The binding type group. internal static void AppendExtraParameters(StringBuilder sb, BindingTypeGroup group) { if (group.HasConversion) { - sb.AppendLine($""" - global::System.Func<{group.SourcePropertyTypeFullName}, {group.TargetPropertyTypeFullName}> vmToViewConverter, - global::System.Func<{group.TargetPropertyTypeFullName}, {group.SourcePropertyTypeFullName}> viewToVmConverter, + _ = sb.AppendLine($""" + global::System.Func<{group.SourcePropertyTypeFullName}, {group.TargetPropertyTypeFullName}> viewModelToViewConverter, + global::System.Func<{group.TargetPropertyTypeFullName}, {group.SourcePropertyTypeFullName}> viewToViewModelConverter, """); } @@ -369,12 +338,10 @@ internal static void AppendExtraParameters(StringBuilder sb, BindingTypeGroup gr return; } - sb.AppendLine(" global::System.Reactive.Concurrency.IScheduler scheduler,"); + _ = sb.AppendLine(" global::System.Reactive.Concurrency.IScheduler scheduler,"); } - /// - /// Formats extra arguments (converters, scheduler) for forwarding to the binding method. - /// + /// Formats extra arguments (converters, scheduler) for forwarding to the binding method. /// The binding type group. /// Extra arguments string or empty. internal static string FormatExtraArgs(BindingTypeGroup group) @@ -382,20 +349,18 @@ internal static string FormatExtraArgs(BindingTypeGroup group) var sb = new StringBuilder(); if (group.HasConversion) { - sb.Append(", vmToViewConverter, viewToVmConverter"); + _ = sb.Append(", viewModelToViewConverter, viewToViewModelConverter"); } if (group.HasScheduler) { - sb.Append(", scheduler"); + _ = sb.Append(", scheduler"); } return sb.ToString(); } - /// - /// Formats extra method parameters for the private binding method signature. - /// + /// Formats extra method parameters for the private binding method signature. /// The binding invocation info. /// Extra parameters string for converter and scheduler parameters. internal static string FormatExtraMethodParams(BindingInvocationInfo inv) @@ -403,32 +368,28 @@ internal static string FormatExtraMethodParams(BindingInvocationInfo inv) var sb = new StringBuilder(); if (inv.HasConversion) { - sb.Append( - $", global::System.Func<{inv.SourcePropertyTypeFullName}, {inv.TargetPropertyTypeFullName}> vmToViewConverter") + _ = sb.Append( + $", global::System.Func<{inv.SourcePropertyTypeFullName}, {inv.TargetPropertyTypeFullName}> viewModelToViewConverter") .Append( - $", global::System.Func<{inv.TargetPropertyTypeFullName}, {inv.SourcePropertyTypeFullName}> viewToVmConverter"); + $", global::System.Func<{inv.TargetPropertyTypeFullName}, {inv.SourcePropertyTypeFullName}> viewToViewModelConverter"); } if (inv.HasScheduler) { - sb.Append(", global::System.Reactive.Concurrency.IScheduler scheduler"); + _ = sb.Append(", global::System.Reactive.Concurrency.IScheduler scheduler"); } return sb.ToString(); } - /// - /// Formats the return type for a concrete Bind overload. - /// + /// Formats the return type for a concrete Bind overload. /// The binding type group. /// The fully qualified return type string. /// Whether the target supports nullable reference types (C# 8+). internal static string FormatReturnType(BindingTypeGroup group, bool supportsNullable) => $"global::ReactiveUI.Binding.IReactiveBinding<{group.TargetTypeFullName}, {BindReturnValueType(supportsNullable)}>"; - /// - /// Formats the return type for a private Bind method. - /// + /// Formats the return type for a private Bind method. /// The binding invocation info. /// The fully qualified return type string. /// Whether the target supports nullable reference types (C# 8+). @@ -436,28 +397,65 @@ internal static string FormatMethodReturnType(BindingInvocationInfo inv, bool su $"global::ReactiveUI.Binding.IReactiveBinding<{inv.TargetTypeFullName}, {BindReturnValueType(supportsNullable)}>"; /// - /// Emits the two-way subscription, change-stream merge, and ReactiveBinding return block. + /// Emits the conversion and scheduler stages that sit between the raw observations and the + /// subscription, and reports the variable names the subscription should read from. /// /// The string builder to append to. /// The binding invocation info. - /// The view model observable variable name to subscribe to. + /// The view model and view observable variable names after the stages are applied. + private static (string ViewModelVar, string ViewVar) EmitConversionAndSchedulerStages( + StringBuilder sb, + BindingInvocationInfo inv) + { + var viewModelVar = ViewModelObservableName; + var viewVar = ViewObservableName; + + if (inv.HasConversion) + { + var viewModelNext = inv.HasScheduler ? "__vmSelected" : "vmBind"; + var viewNext = inv.HasScheduler ? "__viewSelected" : "viewBind"; + _ = sb.AppendLine($""" + var {viewModelNext} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({viewModelVar}, viewModelToViewConverter); + var {viewNext} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({viewVar}, viewToViewModelConverter); + """); + viewModelVar = viewModelNext; + viewVar = viewNext; + } + + if (inv.HasScheduler) + { + _ = sb.AppendLine($""" + var vmBind = new global::ReactiveUI.Binding.Reactive.ObserveOnObservable<{inv.TargetPropertyTypeFullName}>({viewModelVar}, scheduler); + var viewBind = new global::ReactiveUI.Binding.Reactive.ObserveOnObservable<{inv.SourcePropertyTypeFullName}>({viewVar}, scheduler); + """); + viewModelVar = "vmBind"; + viewVar = "viewBind"; + } + + return (viewModelVar, viewVar); + } + + /// Emits the two-way subscription, change-stream merge, and ReactiveBinding return block. + /// The string builder to append to. + /// The binding invocation info. + /// The view model observable variable name to subscribe to. /// The view observable variable name to subscribe to. /// The view property setter access chain. - /// The view model property setter access chain. + /// The view model property setter access chain. /// Whether the target supports nullable reference types (C# 8+). private static void EmitTwoWaySubscription( StringBuilder sb, BindingInvocationInfo inv, - string vmVar, + string viewModelVar, string viewVar, string viewPropertyAccess, - string vmSetAccess, + string viewModelSetAccess, bool supportsNullable) { var nullable = supportsNullable ? "?" : string.Empty; - sb.AppendLine($$""" + _ = sb.AppendLine($$""" - var d1 = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Subscribe({{vmVar}}, value => + var d1 = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Subscribe({{viewModelVar}}, value => { {{viewPropertyAccess}} = value; }); @@ -465,10 +463,10 @@ private static void EmitTwoWaySubscription( var __viewSkipped = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Skip({{viewVar}}, 1); var d2 = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Subscribe(__viewSkipped, value => { - {{vmSetAccess}} = value; + {{viewModelSetAccess}} = value; }); - var __vmTagged = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({{vmVar}}, v => ((object{{nullable}})v, true)); + var __vmTagged = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({{viewModelVar}}, v => ((object{{nullable}})v, true)); var __viewTagged = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select(__viewSkipped, v => ((object{{nullable}})v, false)); var changed = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Merge(__vmTagged, __viewTagged); @@ -494,9 +492,14 @@ private static void EmitTwoWaySubscription( private static string BindReturnValueType(bool supportsNullable) => supportsNullable ? "(object? view, bool isViewModel)" : "(object view, bool isViewModel)"; - /// - /// Groups binding invocations by source, target, property types, and overload variant for overload generation. - /// + /// Groups binding invocations by source, target, property types, and overload variant for overload generation. + /// The fully qualified source (view model) type. + /// The fully qualified target (view) type. + /// The fully qualified type of the bound source property. + /// The fully qualified type of the bound target property. + /// Whether the overload takes a conversion function. + /// Whether the overload takes a scheduler. + /// The call sites sharing this group's shape. internal sealed record BindingTypeGroup( string SourceTypeFullName, string TargetTypeFullName, diff --git a/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/BindCommandCodeGenerator.cs b/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/BindCommandCodeGenerator.cs index 0b2217e..573f2b2 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/BindCommandCodeGenerator.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/BindCommandCodeGenerator.cs @@ -9,14 +9,10 @@ namespace ReactiveUI.Binding.SourceGenerators.CodeGeneration; -/// -/// Generates concrete typed extension method overloads and binding methods for BindCommand invocations. -/// +/// Generates concrete typed extension method overloads and binding methods for BindCommand invocations. internal static class BindCommandCodeGenerator { - /// - /// Generates concrete typed overloads and binding methods for BindCommand invocations. - /// + /// Generates concrete typed overloads and binding methods for BindCommand invocations. /// All detected BindCommand invocations. /// All detected class binding info. /// The consumer compilation's C# language-feature snapshot (dispatch strategy and nullable support). @@ -31,10 +27,10 @@ internal static class BindCommandCodeGenerator return null; } - var sb = new StringBuilder(invocations.Length * 1_024); + var sb = new StringBuilder(invocations.Length * CodeGeneratorHelpers.PerInvocationBufferCapacity); var supportsCallerArgExpr = features.SupportsCallerArgExpr; CodeGeneratorHelpers.AppendExtensionClassHeader(sb, features); - sb.AppendLine(); + _ = sb.AppendLine(); var groups = GroupByTypeSignature(invocations); @@ -43,42 +39,40 @@ internal static class BindCommandCodeGenerator var group = groups[g]; GenerateConcreteOverload(sb, group, supportsCallerArgExpr, features.SupportsNullable); - sb.AppendLine(); + _ = sb.AppendLine(); for (var i = 0; i < group.Invocations.Length; i++) { var inv = group.Invocations[i]; - var vmClassInfo = CodeGeneratorHelpers.FindClassInfo(allClasses, inv.ViewModelTypeFullName); + var viewModelClassInfo = CodeGeneratorHelpers.FindClassInfo(allClasses, inv.ViewModelTypeFullName); var suffix = CodeGeneratorHelpers.ComputeStableMethodSuffix( inv.ViewTypeFullName, inv.CallerFilePath, inv.CallerLineNumber, - inv.CommandExpressionText + "|" + inv.ControlExpressionText); - GenerateBindCommandMethod(sb, inv, vmClassInfo, suffix, features.SupportsNullable); + $"{inv.CommandExpressionText}|{inv.ControlExpressionText}"); + GenerateBindCommandMethod(sb, inv, viewModelClassInfo, suffix, features.SupportsNullable); } } CodeGeneratorHelpers.AppendExtensionClassFooter(sb); - sb.AppendLine(); + _ = sb.AppendLine(); return sb.ToString(); } - /// - /// Groups BindCommand invocations by their type signature for overload generation. - /// + /// Groups BindCommand invocations by their type signature for overload generation. /// The BindCommand invocations to group. /// A list of grouped invocations sharing the same type signature. internal static List GroupByTypeSignature( ImmutableArray invocations) { var groupMap = new Dictionary>(invocations.Length); - var keySb = new StringBuilder(128); + var keySb = new StringBuilder(CodeGeneratorHelpers.FragmentBufferCapacity); for (var i = 0; i < invocations.Length; i++) { var inv = invocations[i]; - keySb.Clear() + _ = keySb.Clear() .Append(inv.ViewTypeFullName).Append('|') .Append(inv.ViewModelTypeFullName).Append('|') .Append(inv.CommandTypeFullName).Append('|') @@ -116,9 +110,7 @@ internal static List GroupByTypeSignature( return result; } - /// - /// Generates the concrete typed overload using the appropriate dispatch strategy. - /// + /// Generates the concrete typed overload using the appropriate dispatch strategy. /// The string builder to append to. /// The BindCommand type group. /// Whether CallerArgumentExpression is available. @@ -139,9 +131,7 @@ internal static void GenerateConcreteOverload( } } - /// - /// Generates the CallerArgumentExpression-based overload for BindCommand dispatch. - /// + /// Generates the CallerArgumentExpression-based overload for BindCommand dispatch. /// The string builder to append to. /// The BindCommand type group. /// Whether the target supports nullable reference types (C# 8+). @@ -160,9 +150,9 @@ internal static void GenerateCallerArgExprOverload( // The expression-form command-parameter selector is nullable for reference-type parameters, matching the // runtime stub's Expression> so the parameter lambda may return null without CS8603. var withParameterExprType = supportsNullable && group.Invocations[0].ParameterIsReferenceType - ? group.ParameterTypeFullName + "?" + ? $"{group.ParameterTypeFullName}?" : group.ParameterTypeFullName; - sb.AppendLine($""" + _ = sb.AppendLine($""" /// /// Concrete typed overload for BindCommand on {group.ViewTypeFullName}. /// Uses CallerArgumentExpression for dispatch. @@ -176,15 +166,15 @@ internal static void GenerateCallerArgExprOverload( if (group.HasObservableParameter) { - sb.AppendLine($" global::System.IObservable<{group.ParameterTypeFullName}> withParameter,"); + _ = sb.AppendLine($" global::System.IObservable<{group.ParameterTypeFullName}> withParameter,"); } else if (group.HasExpressionParameter) { - sb.AppendLine( + _ = sb.AppendLine( $" global::System.Linq.Expressions.Expression> withParameter,"); } - sb.AppendLine($""" + _ = sb.AppendLine($""" string{(supportsNullable ? "?" : string.Empty)} toEvent = null, [global::System.Runtime.CompilerServices.CallerArgumentExpression("propertyName")] string propertyNameExpression = "", [global::System.Runtime.CompilerServices.CallerArgumentExpression("controlName")] string controlNameExpression = "", @@ -192,12 +182,12 @@ internal static void GenerateCallerArgExprOverload( if (group.HasExpressionParameter) { - sb.AppendLine(""" + _ = sb.AppendLine(""" [global::System.Runtime.CompilerServices.CallerArgumentExpression("withParameter")] string withParameterExpression = "", """); } - sb.AppendLine(""" + _ = sb.AppendLine(""" [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { @@ -206,41 +196,11 @@ internal static void GenerateCallerArgExprOverload( """); - for (var i = 0; i < group.Invocations.Length; i++) - { - var inv = group.Invocations[i]; - var methodSuffix = CodeGeneratorHelpers.ComputeStableMethodSuffix( - inv.ViewTypeFullName, - inv.CallerFilePath, - inv.CallerLineNumber, - inv.CommandExpressionText + "|" + inv.ControlExpressionText); - var condition = CodeGeneratorHelpers.ConditionKeyword(i); - var escapedCmdExpr = CodeGeneratorHelpers.EscapeString(inv.CommandExpressionText); - var escapedCtrlExpr = CodeGeneratorHelpers.EscapeString(inv.ControlExpressionText); - - var extraArgs = group.HasObservableParameter - ? ", withParameter" - : string.Empty; - - sb.AppendLine($$""" - {{condition}} (propertyNameExpression == "{{escapedCmdExpr}}" - && controlNameExpression == "{{escapedCtrlExpr}}") - { - return __BindCommand_{{methodSuffix}}(view, viewModel{{extraArgs}}); - } - """); - } - - sb.AppendLine(""" - throw new global::System.InvalidOperationException( - "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); - } - """); + EmitExpressionDispatchBranches(sb, group); + EmitDispatchFallthrough(sb); } - /// - /// Generates the CallerFilePath-based overload for BindCommand dispatch. - /// + /// Generates the CallerFilePath-based overload for BindCommand dispatch. /// The string builder to append to. /// The BindCommand type group. /// Whether the target supports nullable reference types (C# 8+). @@ -259,9 +219,9 @@ internal static void GenerateCallerFilePathOverload( // The expression-form command-parameter selector is nullable for reference-type parameters, matching the // runtime stub's Expression> so the parameter lambda may return null without CS8603. var withParameterExprType = supportsNullable && group.Invocations[0].ParameterIsReferenceType - ? group.ParameterTypeFullName + "?" + ? $"{group.ParameterTypeFullName}?" : group.ParameterTypeFullName; - sb.AppendLine($""" + _ = sb.AppendLine($""" /// /// Concrete typed overload for BindCommand on {group.ViewTypeFullName}. /// Uses CallerFilePath + CallerLineNumber for dispatch. @@ -275,64 +235,35 @@ internal static void GenerateCallerFilePathOverload( if (group.HasObservableParameter) { - sb.AppendLine($" global::System.IObservable<{group.ParameterTypeFullName}> withParameter,"); + _ = sb.AppendLine($" global::System.IObservable<{group.ParameterTypeFullName}> withParameter,"); } else if (group.HasExpressionParameter) { - sb.AppendLine( + _ = sb.AppendLine( $" global::System.Linq.Expressions.Expression> withParameter,"); } - sb.AppendLine($$""" + _ = sb.AppendLine($$""" string{{(supportsNullable ? "?" : string.Empty)}} toEvent = null, [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { """); - for (var i = 0; i < group.Invocations.Length; i++) - { - var inv = group.Invocations[i]; - var methodSuffix = CodeGeneratorHelpers.ComputeStableMethodSuffix( - inv.ViewTypeFullName, - inv.CallerFilePath, - inv.CallerLineNumber, - inv.CommandExpressionText + "|" + inv.ControlExpressionText); - var pathSuffix = CodeGeneratorHelpers.ComputePathSuffix(inv.CallerFilePath); - var condition = CodeGeneratorHelpers.ConditionKeyword(i); - - var extraArgs = group.HasObservableParameter - ? ", withParameter" - : string.Empty; - - sb.AppendLine($$""" - {{condition}} (callerLineNumber == {{inv.CallerLineNumber}} - && callerFilePath.EndsWith("{{CodeGeneratorHelpers.EscapeString(pathSuffix)}}", global::System.StringComparison.OrdinalIgnoreCase)) - { - return __BindCommand_{{methodSuffix}}(view, viewModel{{extraArgs}}); - } - """); - } - - sb.AppendLine(""" - throw new global::System.InvalidOperationException( - "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); - } - """); + EmitFilePathDispatchBranches(sb, group); + EmitDispatchFallthrough(sb); } - /// - /// Generates a private BindCommand method for a specific invocation. - /// + /// Generates a private BindCommand method for a specific invocation. /// The string builder to append to. /// The BindCommand invocation info. - /// The view model type class binding info. + /// The view model type class binding info. /// The stable method name suffix. /// There can be a null type. internal static void GenerateBindCommandMethod( StringBuilder sb, BindCommandInvocationInfo inv, - ClassBindingInfo? vmClassInfo, + ClassBindingInfo? viewModelClassInfo, string suffix, bool supportsNullable) { @@ -346,7 +277,7 @@ internal static void GenerateBindCommandMethod( ? $", global::System.IObservable<{inv.ParameterTypeFullName}> withParameter" : string.Empty; - sb.AppendLine($$""" + _ = sb.AppendLine($$""" private static global::System.IDisposable __BindCommand_{{suffix}}( {{inv.ViewTypeFullName}} view, {{inv.ViewModelTypeFullName}} viewModel{{extraParams}}) @@ -368,7 +299,7 @@ internal static void GenerateBindCommandMethod( "viewModel", inv.CommandPropertyPath, inv.CommandTypeFullName, - vmClassInfo, + viewModelClassInfo, "commandObs"); // Try plugins in affinity order (highest first) via registry @@ -387,14 +318,14 @@ internal static void GenerateBindCommandMethod( else { // No plugin matched — throw after the affinity check fallback - sb.AppendLine(""" + _ = sb.AppendLine(""" throw new global::System.InvalidOperationException( "No bindable event found on the control. Specify the 'toEvent' parameter."); } """); } - sb.AppendLine(); + _ = sb.AppendLine(); } /// @@ -418,7 +349,7 @@ internal static void EmitCommandAffinityCheck( // Build the parameter observable expression for the custom binder var paramObsExpr = BuildParameterObservableExpression(inv); - sb.AppendLine($$""" + _ = sb.AppendLine($$""" if (global::ReactiveUI.Binding.Fallback.CommandBindingAffinityChecker .HasHigherAffinityPlugin<{{inv.ControlTypeFullName}}>({{generatedAffinity}}, {{(hasEvent ? "true" : "false")}})) @@ -443,9 +374,7 @@ internal static void EmitCommandAffinityCheck( """); } - /// - /// Builds the parameter observable expression string for custom binder fallback code. - /// + /// Builds the parameter observable expression string for custom binder fallback code. /// The BindCommand invocation info. /// The parameter observable expression to embed in generated code. internal static string BuildParameterObservableExpression(BindCommandInvocationInfo inv) @@ -453,8 +382,7 @@ internal static string BuildParameterObservableExpression(BindCommandInvocationI if (inv.HasObservableParameter) { // Cast the typed observable to IObservable via Select - return "new global::ReactiveUI.Binding.Observables.SelectObservable<" - + inv.ParameterTypeFullName + ", object>(withParameter, __p => __p)"; + return $"new global::ReactiveUI.Binding.Observables.SelectObservable<{inv.ParameterTypeFullName}, object>(withParameter, __p => __p)"; } if (inv is { HasExpressionParameter: true, ParameterPropertyPath: not null }) @@ -462,15 +390,87 @@ internal static string BuildParameterObservableExpression(BindCommandInvocationI // Read the parameter property at call time var paramAccess = CodeGeneratorHelpers.BuildPropertyAccessChain("viewModel", inv.ParameterPropertyPath.Value); - return "new global::ReactiveUI.Binding.Observables.ReturnObservable(" + paramAccess + ")"; + return $"new global::ReactiveUI.Binding.Observables.ReturnObservable({paramAccess})"; } return "global::ReactiveUI.Binding.Observables.EmptyObservable.Instance"; } - /// - /// Groups BindCommand invocations by type signature for overload generation. - /// + /// Emits one expression-text comparison branch per call site in the group. + /// The string builder to append to. + /// The BindCommand type group. + private static void EmitExpressionDispatchBranches(StringBuilder sb, BindCommandTypeGroup group) + { + var extraArgs = group.HasObservableParameter ? ", withParameter" : string.Empty; + + for (var i = 0; i < group.Invocations.Length; i++) + { + var inv = group.Invocations[i]; + var methodSuffix = CodeGeneratorHelpers.ComputeStableMethodSuffix( + inv.ViewTypeFullName, + inv.CallerFilePath, + inv.CallerLineNumber, + $"{inv.CommandExpressionText}|{inv.ControlExpressionText}"); + var condition = CodeGeneratorHelpers.ConditionKeyword(i); + var escapedCmdExpr = CodeGeneratorHelpers.EscapeString(inv.CommandExpressionText); + var escapedCtrlExpr = CodeGeneratorHelpers.EscapeString(inv.ControlExpressionText); + + _ = sb.AppendLine($$""" + {{condition}} (propertyNameExpression == "{{escapedCmdExpr}}" + && controlNameExpression == "{{escapedCtrlExpr}}") + { + return __BindCommand_{{methodSuffix}}(view, viewModel{{extraArgs}}); + } + """); + } + } + + /// Emits the throw that closes a dispatch method when no call site matched. + /// The string builder to append to. + private static void EmitDispatchFallthrough(StringBuilder sb) => + _ = sb.AppendLine(""" + throw new global::System.InvalidOperationException( + "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); + } + """); + + /// Emits one file-and-line comparison branch per call site in the group. + /// The string builder to append to. + /// The BindCommand type group. + private static void EmitFilePathDispatchBranches(StringBuilder sb, BindCommandTypeGroup group) + { + var extraArgs = group.HasObservableParameter ? ", withParameter" : string.Empty; + + for (var i = 0; i < group.Invocations.Length; i++) + { + var inv = group.Invocations[i]; + var methodSuffix = CodeGeneratorHelpers.ComputeStableMethodSuffix( + inv.ViewTypeFullName, + inv.CallerFilePath, + inv.CallerLineNumber, + $"{inv.CommandExpressionText}|{inv.ControlExpressionText}"); + var pathSuffix = CodeGeneratorHelpers.ComputePathSuffix(inv.CallerFilePath); + var condition = CodeGeneratorHelpers.ConditionKeyword(i); + + _ = sb.AppendLine($$""" + {{condition}} (callerLineNumber == {{inv.CallerLineNumber}} + && callerFilePath.EndsWith("{{CodeGeneratorHelpers.EscapeString(pathSuffix)}}", global::System.StringComparison.OrdinalIgnoreCase)) + { + return __BindCommand_{{methodSuffix}}(view, viewModel{{extraArgs}}); + } + """); + } + } + + /// Groups BindCommand invocations by type signature for overload generation. + /// The fully qualified view type. + /// The fully qualified view model type. + /// The fully qualified type of the bound command property. + /// The fully qualified type of the control the command binds to. + /// Whether the overload takes an observable command parameter. + /// Whether the overload takes an expression command parameter. + /// The fully qualified command parameter type, when the overload has one. + /// The call sites sharing this group's shape. internal sealed record BindCommandTypeGroup( string ViewTypeFullName, string ViewModelTypeFullName, diff --git a/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/BindInteractionCodeGenerator.cs b/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/BindInteractionCodeGenerator.cs index c254eb5..914f750 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/BindInteractionCodeGenerator.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/BindInteractionCodeGenerator.cs @@ -10,14 +10,10 @@ namespace ReactiveUI.Binding.SourceGenerators.CodeGeneration; -/// -/// Generates concrete typed extension method overloads and binding methods for BindInteraction invocations. -/// +/// Generates concrete typed extension method overloads and binding methods for BindInteraction invocations. internal static class BindInteractionCodeGenerator { - /// - /// Generates concrete typed overloads and binding methods for BindInteraction invocations. - /// + /// Generates concrete typed overloads and binding methods for BindInteraction invocations. /// All detected BindInteraction invocations. /// All detected class binding info. /// The consumer compilation's C# language-feature snapshot (dispatch strategy and nullable support). @@ -32,10 +28,10 @@ internal static class BindInteractionCodeGenerator return null; } - var sb = new StringBuilder(invocations.Length * 1_024); + var sb = new StringBuilder(invocations.Length * CodeGeneratorHelpers.PerInvocationBufferCapacity); var supportsCallerArgExpr = features.SupportsCallerArgExpr; CodeGeneratorHelpers.AppendExtensionClassHeader(sb, features); - sb.AppendLine(); + _ = sb.AppendLine(); var groups = GroupByTypeSignature(invocations); @@ -44,42 +40,40 @@ internal static class BindInteractionCodeGenerator var group = groups[g]; GenerateConcreteOverload(sb, group, supportsCallerArgExpr); - sb.AppendLine(); + _ = sb.AppendLine(); for (var i = 0; i < group.Invocations.Length; i++) { var inv = group.Invocations[i]; - var vmClassInfo = CodeGeneratorHelpers.FindClassInfo(allClasses, inv.ViewModelTypeFullName); + var viewModelClassInfo = CodeGeneratorHelpers.FindClassInfo(allClasses, inv.ViewModelTypeFullName); var suffix = CodeGeneratorHelpers.ComputeStableMethodSuffix( inv.ViewTypeFullName, inv.CallerFilePath, inv.CallerLineNumber, inv.ExpressionText); - GenerateBindInteractionMethod(sb, inv, vmClassInfo, suffix); + GenerateBindInteractionMethod(sb, inv, viewModelClassInfo, suffix); } } CodeGeneratorHelpers.AppendExtensionClassFooter(sb); - sb.AppendLine(); + _ = sb.AppendLine(); return sb.ToString(); } - /// - /// Groups BindInteraction invocations by their type signature for overload generation. - /// + /// Groups BindInteraction invocations by their type signature for overload generation. /// The BindInteraction invocations to group. /// A list of grouped invocations sharing the same type signature. internal static List GroupByTypeSignature( ImmutableArray invocations) { var groupMap = new Dictionary>(invocations.Length); - var keySb = new StringBuilder(128); + var keySb = new StringBuilder(CodeGeneratorHelpers.FragmentBufferCapacity); for (var i = 0; i < invocations.Length; i++) { var inv = invocations[i]; - keySb.Clear() + _ = keySb.Clear() .Append(inv.ViewTypeFullName).Append('|') .Append(inv.ViewModelTypeFullName).Append('|') .Append(inv.InputTypeFullName).Append('|') @@ -114,9 +108,7 @@ internal static List GroupByTypeSignature( return result; } - /// - /// Generates the concrete typed overload using the appropriate dispatch strategy. - /// + /// Generates the concrete typed overload using the appropriate dispatch strategy. /// The string builder to append to. /// The BindInteraction type group. /// Whether CallerArgumentExpression is available. @@ -135,9 +127,7 @@ internal static void GenerateConcreteOverload( } } - /// - /// Generates the CallerArgumentExpression-based overload for BindInteraction dispatch. - /// + /// Generates the CallerArgumentExpression-based overload for BindInteraction dispatch. /// The string builder to append to. /// The BindInteraction type group. internal static void GenerateCallerArgExprOverload( @@ -148,7 +138,7 @@ internal static void GenerateCallerArgExprOverload( ? $"global::System.Func, global::System.Threading.Tasks.Task>" : $"global::System.Func, global::System.IObservable<{group.DontCareTypeFullName}>>"; - sb.AppendLine($$""" + _ = sb.AppendLine($$""" /// /// Concrete typed overload for BindInteraction on {{group.ViewTypeFullName}}. /// Uses CallerArgumentExpression for dispatch. @@ -177,7 +167,7 @@ internal static void GenerateCallerArgExprOverload( var condition = CodeGeneratorHelpers.ConditionKeyword(i); var escapedExpr = CodeGeneratorHelpers.EscapeString(inv.ExpressionText); - sb.AppendLine($$""" + _ = sb.AppendLine($$""" {{condition}} (propertyNameExpression == "{{escapedExpr}}") { return __BindInteraction_{{methodSuffix}}(viewModel, handler); @@ -185,16 +175,14 @@ internal static void GenerateCallerArgExprOverload( """); } - sb.AppendLine(""" + _ = sb.AppendLine(""" throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } """); } - /// - /// Generates the CallerFilePath-based overload for BindInteraction dispatch. - /// + /// Generates the CallerFilePath-based overload for BindInteraction dispatch. /// The string builder to append to. /// The BindInteraction type group. internal static void GenerateCallerFilePathOverload( @@ -205,7 +193,7 @@ internal static void GenerateCallerFilePathOverload( ? $"global::System.Func, global::System.Threading.Tasks.Task>" : $"global::System.Func, global::System.IObservable<{group.DontCareTypeFullName}>>"; - sb.AppendLine($$""" + _ = sb.AppendLine($$""" /// /// Concrete typed overload for BindInteraction on {{group.ViewTypeFullName}}. /// Uses CallerFilePath + CallerLineNumber for dispatch. @@ -231,7 +219,7 @@ internal static void GenerateCallerFilePathOverload( var pathSuffix = CodeGeneratorHelpers.ComputePathSuffix(inv.CallerFilePath); var condition = CodeGeneratorHelpers.ConditionKeyword(i); - sb.AppendLine($$""" + _ = sb.AppendLine($$""" {{condition}} (callerLineNumber == {{inv.CallerLineNumber}} && callerFilePath.EndsWith("{{CodeGeneratorHelpers.EscapeString(pathSuffix)}}", global::System.StringComparison.OrdinalIgnoreCase)) { @@ -240,24 +228,22 @@ internal static void GenerateCallerFilePathOverload( """); } - sb.AppendLine(""" + _ = sb.AppendLine(""" throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } """); } - /// - /// Generates a private BindInteraction method for a specific invocation. - /// + /// Generates a private BindInteraction method for a specific invocation. /// The string builder to append to. /// The BindInteraction invocation info. - /// The view model type class binding info. + /// The view model type class binding info. /// The stable method name suffix. internal static void GenerateBindInteractionMethod( StringBuilder sb, BindInteractionInvocationInfo inv, - ClassBindingInfo? vmClassInfo, + ClassBindingInfo? viewModelClassInfo, string suffix) { var handlerType = inv.IsTaskHandler @@ -268,7 +254,7 @@ internal static void GenerateBindInteractionMethod( $"global::ReactiveUI.Binding.IInteraction<{inv.InputTypeFullName}, {inv.OutputTypeFullName}>"; var pathComment = CodeGeneratorHelpers.BuildPropertyPathString(inv.InteractionPropertyPath); - sb.AppendLine($$""" + _ = sb.AppendLine($$""" private static global::System.IDisposable __BindInteraction_{{suffix}}( {{inv.ViewModelTypeFullName}} viewModel, {{handlerType}} handler) @@ -278,58 +264,12 @@ internal static void GenerateBindInteractionMethod( """); - // Emit inline observation of the interaction property on the view model - // We need to handle the case where viewModel is null - if (inv.InteractionPropertyPath.Length == 1) - { - var propertyName = inv.InteractionPropertyPath[0].PropertyName; - var isINPC = ObservationCodeGenerator.IsINPC(vmClassInfo); - - sb.AppendLine(isINPC - ? $$""" - if (viewModel == null) - { - return serial; - } - - var interactionObs = new global::ReactiveUI.Binding.Observables.PropertyObservable<{{interactionType}}>( - viewModel, - "{{propertyName}}", - (global::System.ComponentModel.INotifyPropertyChanged __o) => (({{inv.ViewModelTypeFullName}})__o).{{propertyName}}, - true); - """ - : $$""" - if (viewModel == null) - { - return serial; - } - - var interactionObs = new global::ReactiveUI.Binding.Observables.ReturnObservable<{{interactionType}}>(viewModel.{{propertyName}}); - """); - } - else - { - // Deep path — emit full chain observation using ObservationCodeGenerator pattern - sb.AppendLine(""" - if (viewModel == null) - { - return serial; - } - """); - - ObservationCodeGenerator.EmitInlineObservation( - sb, - "viewModel", - inv.InteractionPropertyPath, - interactionType, - vmClassInfo, - "interactionObs"); - } + EmitInteractionObservation(sb, inv, viewModelClassInfo, interactionType); // Subscribe to the interaction observable and register the handler const string registerCall = "interaction.RegisterHandler(handler)"; - sb.AppendLine($$""" + _ = sb.AppendLine($$""" var sub = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Subscribe(interactionObs, interaction => { @@ -344,8 +284,71 @@ internal static void GenerateBindInteractionMethod( } /// - /// Groups BindInteraction invocations by type signature for overload generation. + /// Emits the null guard and the observation of the interaction property. A single-segment path + /// observes the property directly; a deeper path delegates to the shared chain emitter. /// + /// The string builder to append to. + /// The BindInteraction invocation info. + /// The view model type's binding info, when known. + /// The fully qualified interaction type being observed. + private static void EmitInteractionObservation( + StringBuilder sb, + BindInteractionInvocationInfo inv, + ClassBindingInfo? viewModelClassInfo, + string interactionType) + { + if (inv.InteractionPropertyPath.Length != 1) + { + _ = sb.AppendLine(""" + if (viewModel == null) + { + return serial; + } + """); + + ObservationCodeGenerator.EmitInlineObservation( + sb, + "viewModel", + inv.InteractionPropertyPath, + interactionType, + viewModelClassInfo, + "interactionObs"); + return; + } + + var propertyName = inv.InteractionPropertyPath[0].PropertyName; + + _ = sb.AppendLine(ObservationCodeGenerator.IsINPC(viewModelClassInfo) + ? $$""" + if (viewModel == null) + { + return serial; + } + + var interactionObs = new global::ReactiveUI.Binding.Observables.PropertyObservable<{{interactionType}}>( + viewModel, + "{{propertyName}}", + (global::System.ComponentModel.INotifyPropertyChanged __o) => (({{inv.ViewModelTypeFullName}})__o).{{propertyName}}, + true); + """ + : $$""" + if (viewModel == null) + { + return serial; + } + + var interactionObs = new global::ReactiveUI.Binding.Observables.ReturnObservable<{{interactionType}}>(viewModel.{{propertyName}}); + """); + } + + /// Groups BindInteraction invocations by type signature for overload generation. + /// The fully qualified view type. + /// The fully qualified view model type. + /// The fully qualified interaction input type. + /// The fully qualified interaction output type. + /// Whether the handler returns a task rather than an observable. + /// The fully qualified handler result type that the binding discards, when there is one. + /// The call sites sharing this group's shape. internal sealed record BindInteractionTypeGroup( string ViewTypeFullName, string ViewModelTypeFullName, diff --git a/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/BindOneWayCodeGenerator.cs b/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/BindOneWayCodeGenerator.cs index f2bb81b..beb2f71 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/BindOneWayCodeGenerator.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/BindOneWayCodeGenerator.cs @@ -14,9 +14,10 @@ namespace ReactiveUI.Binding.SourceGenerators.CodeGeneration; /// internal static class BindOneWayCodeGenerator { - /// - /// Generates concrete typed overloads and binding methods for BindOneWay invocations. - /// + /// Name of the emitted local holding the source property observation, before conversion or scheduling. + private const string SourceObservableVariable = "sourceObs"; + + /// Generates concrete typed overloads and binding methods for BindOneWay invocations. /// All detected BindOneWay invocations. /// All detected class binding info. /// The consumer compilation's C# language-feature snapshot (dispatch strategy and nullable support). @@ -31,10 +32,10 @@ internal static class BindOneWayCodeGenerator return null; } - var sb = new StringBuilder(invocations.Length * 1_024); + var sb = new StringBuilder(invocations.Length * CodeGeneratorHelpers.PerInvocationBufferCapacity); var supportsCallerArgExpr = features.SupportsCallerArgExpr; CodeGeneratorHelpers.AppendExtensionClassHeader(sb, features); - sb.AppendLine(); + _ = sb.AppendLine(); // Group invocations by (SourceType, TargetType, SourcePropertyType, TargetPropertyType, HasConversion, HasScheduler) var groups = GroupByTypeSignature(invocations); @@ -45,7 +46,7 @@ internal static class BindOneWayCodeGenerator // Generate the concrete typed extension method overload GenerateConcreteOverload(sb, group, supportsCallerArgExpr, features.SupportsNullable); - sb.AppendLine(); + _ = sb.AppendLine(); // Generate binding methods for (var i = 0; i < group.Invocations.Length; i++) @@ -56,31 +57,29 @@ internal static class BindOneWayCodeGenerator inv.SourceTypeFullName, inv.CallerFilePath, inv.CallerLineNumber, - inv.SourceExpressionText + "|" + inv.TargetExpressionText); + $"{inv.SourceExpressionText}|{inv.TargetExpressionText}"); GenerateBindOneWayMethod(sb, inv, sourceClassInfo, suffix); } } CodeGeneratorHelpers.AppendExtensionClassFooter(sb); - sb.AppendLine(); + _ = sb.AppendLine(); return sb.ToString(); } - /// - /// Groups binding invocation information by a unique type signature, producing a collection of grouped results. - /// + /// Groups binding invocation information by a unique type signature, producing a collection of grouped results. /// The collection of binding invocation details to be grouped. /// A list of grouped binding type information, where each group shares the same type signature. internal static List GroupByTypeSignature(ImmutableArray invocations) { var groupMap = new Dictionary>(invocations.Length); - var keySb = new StringBuilder(128); + var keySb = new StringBuilder(CodeGeneratorHelpers.FragmentBufferCapacity); for (var i = 0; i < invocations.Length; i++) { var inv = invocations[i]; - keySb.Clear() + _ = keySb.Clear() .Append(inv.SourceTypeFullName).Append('|') .Append(inv.TargetTypeFullName).Append('|') .Append(inv.SourcePropertyTypeFullName).Append('|') @@ -154,7 +153,7 @@ internal static void GenerateCallerArgExprOverload( { var sourcePropType = CodeGeneratorHelpers.NullableSelectorLeafType(group.Invocations[0].SourcePropertyPath, supportsNullable); var targetPropType = CodeGeneratorHelpers.NullableSelectorLeafType(group.Invocations[0].TargetPropertyPath, supportsNullable); - sb.AppendLine($""" + _ = sb.AppendLine($""" /// /// Concrete typed overload for BindOneWay from {group.SourceTypeFullName} to {group.TargetTypeFullName}. /// Uses CallerArgumentExpression for dispatch. @@ -168,7 +167,7 @@ internal static void GenerateCallerArgExprOverload( AppendExtraParameters(sb, group); - sb.AppendLine(""" + _ = sb.AppendLine(""" [global::System.Runtime.CompilerServices.CallerArgumentExpression("sourceProperty")] string sourcePropertyExpression = "", [global::System.Runtime.CompilerServices.CallerArgumentExpression("targetProperty")] string targetPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", @@ -186,12 +185,12 @@ internal static void GenerateCallerArgExprOverload( inv.SourceTypeFullName, inv.CallerFilePath, inv.CallerLineNumber, - inv.SourceExpressionText + "|" + inv.TargetExpressionText); + $"{inv.SourceExpressionText}|{inv.TargetExpressionText}"); var condition = CodeGeneratorHelpers.ConditionKeyword(i); var escapedSourceExpr = CodeGeneratorHelpers.EscapeString(inv.SourceExpressionText); var escapedTargetExpr = CodeGeneratorHelpers.EscapeString(inv.TargetExpressionText); - sb.AppendLine($$""" + _ = sb.AppendLine($$""" {{condition}} (sourcePropertyExpression == "{{escapedSourceExpr}}" && targetPropertyExpression == "{{escapedTargetExpr}}") { @@ -200,7 +199,7 @@ internal static void GenerateCallerArgExprOverload( """); } - sb.AppendLine(""" + _ = sb.AppendLine(""" throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } @@ -221,7 +220,7 @@ internal static void GenerateCallerFilePathOverload( { var sourcePropType = CodeGeneratorHelpers.NullableSelectorLeafType(group.Invocations[0].SourcePropertyPath, supportsNullable); var targetPropType = CodeGeneratorHelpers.NullableSelectorLeafType(group.Invocations[0].TargetPropertyPath, supportsNullable); - sb.AppendLine($""" + _ = sb.AppendLine($""" /// /// Concrete typed overload for BindOneWay from {group.SourceTypeFullName} to {group.TargetTypeFullName}. /// Uses CallerFilePath + CallerLineNumber for dispatch. @@ -235,7 +234,7 @@ internal static void GenerateCallerFilePathOverload( AppendExtraParameters(sb, group); - sb.AppendLine(""" + _ = sb.AppendLine(""" [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { @@ -248,11 +247,11 @@ internal static void GenerateCallerFilePathOverload( inv.SourceTypeFullName, inv.CallerFilePath, inv.CallerLineNumber, - inv.SourceExpressionText + "|" + inv.TargetExpressionText); + $"{inv.SourceExpressionText}|{inv.TargetExpressionText}"); var pathSuffix = CodeGeneratorHelpers.ComputePathSuffix(inv.CallerFilePath); var condition = CodeGeneratorHelpers.ConditionKeyword(i); - sb.AppendLine($$""" + _ = sb.AppendLine($$""" {{condition}} (callerLineNumber == {{inv.CallerLineNumber}} && callerFilePath.EndsWith("{{CodeGeneratorHelpers.EscapeString(pathSuffix)}}", global::System.StringComparison.OrdinalIgnoreCase)) { @@ -261,7 +260,7 @@ internal static void GenerateCallerFilePathOverload( """); } - sb.AppendLine(""" + _ = sb.AppendLine(""" throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } @@ -289,7 +288,7 @@ internal static void GenerateBindOneWayMethod( var conversionComment = inv.HasConversion ? " (with conversion)" : string.Empty; var schedulerComment = inv.HasScheduler ? " (with scheduler)" : string.Empty; - sb.AppendLine($$""" + _ = sb.AppendLine($$""" private static global::System.IDisposable __BindOneWay_{{suffix}}({{inv.SourceTypeFullName}} source, {{inv.TargetTypeFullName}} target{{extraParams}}) { // BindOneWay: {{sourcePathComment}} -> {{targetPathComment}}{{conversionComment}}{{schedulerComment}} @@ -302,61 +301,31 @@ internal static void GenerateBindOneWayMethod( inv.SourcePropertyPath, inv.SourcePropertyTypeFullName, sourceClassInfo, - "sourceObs"); + SourceObservableVariable); - if (inv.HasConversion || inv.HasScheduler) - { - var currentVar = "sourceObs"; + var subscribeVar = inv.HasConversion || inv.HasScheduler + ? EmitConversionAndSchedulerStages(sb, inv) + : SourceObservableVariable; - if (inv.HasConversion) - { - var nextVar = inv.HasScheduler ? "__selected" : "bindObs"; - sb.AppendLine( - $" var {nextVar} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({currentVar}, conversionFunc);"); - currentVar = nextVar; - } - - if (inv.HasScheduler) - { - sb.AppendLine( - $" var bindObs = new global::ReactiveUI.Binding.Reactive.ObserveOnObservable<{inv.TargetPropertyTypeFullName}>({currentVar}, scheduler);"); - currentVar = "bindObs"; - } + _ = sb.AppendLine($$""" - sb.AppendLine($$""" - - return global::ReactiveUI.Binding.Observables.RxBindingExtensions.Subscribe({{currentVar}}, value => - { - {{targetAccess}} = value; - }); - } - """) - .AppendLine(); - } - else - { - sb.AppendLine($$""" - - return global::ReactiveUI.Binding.Observables.RxBindingExtensions.Subscribe(sourceObs, value => - { - {{targetAccess}} = value; - }); - } - """) - .AppendLine(); - } + return global::ReactiveUI.Binding.Observables.RxBindingExtensions.Subscribe({{subscribeVar}}, value => + { + {{targetAccess}} = value; + }); + } + """) + .AppendLine(); } - /// - /// Appends extra parameters (converter, scheduler) to the concrete overload signature. - /// + /// Appends extra parameters (converter, scheduler) to the concrete overload signature. /// The string builder to append to. /// The binding type group. internal static void AppendExtraParameters(StringBuilder sb, BindingTypeGroup group) { if (group.HasConversion) { - sb.AppendLine( + _ = sb.AppendLine( $" global::System.Func<{group.SourcePropertyTypeFullName}, {group.TargetPropertyTypeFullName}> conversionFunc,"); } @@ -365,12 +334,10 @@ internal static void AppendExtraParameters(StringBuilder sb, BindingTypeGroup gr return; } - sb.AppendLine(" global::System.Reactive.Concurrency.IScheduler scheduler,"); + _ = sb.AppendLine(" global::System.Reactive.Concurrency.IScheduler scheduler,"); } - /// - /// Formats extra arguments (converter, scheduler) for forwarding to the binding method. - /// + /// Formats extra arguments (converter, scheduler) for forwarding to the binding method. /// The binding type group. /// Extra arguments string like ", conversionFunc, scheduler" or empty. internal static string FormatExtraArgs(BindingTypeGroup group) @@ -378,20 +345,18 @@ internal static string FormatExtraArgs(BindingTypeGroup group) var sb = new StringBuilder(); if (group.HasConversion) { - sb.Append(", conversionFunc"); + _ = sb.Append(", conversionFunc"); } if (group.HasScheduler) { - sb.Append(", scheduler"); + _ = sb.Append(", scheduler"); } return sb.ToString(); } - /// - /// Formats extra method parameters for the private binding method signature. - /// + /// Formats extra method parameters for the private binding method signature. /// The binding invocation info. /// Extra parameters string like ", Func<int, string> conversionFunc, IScheduler scheduler" or empty. internal static string FormatExtraMethodParams(BindingInvocationInfo inv) @@ -399,21 +364,45 @@ internal static string FormatExtraMethodParams(BindingInvocationInfo inv) var sb = new StringBuilder(); if (inv.HasConversion) { - sb.Append( + _ = sb.Append( $", global::System.Func<{inv.SourcePropertyTypeFullName}, {inv.TargetPropertyTypeFullName}> conversionFunc"); } if (inv.HasScheduler) { - sb.Append(", global::System.Reactive.Concurrency.IScheduler scheduler"); + _ = sb.Append(", global::System.Reactive.Concurrency.IScheduler scheduler"); } return sb.ToString(); } - /// - /// Groups binding invocations by source, target, property types, and overload variant for overload generation. - /// + /// Emits the conversion and scheduler stages between the source observation and the subscription. + /// The string builder to append to. + /// The binding invocation info. + /// The variable name the subscription should read from. + private static string EmitConversionAndSchedulerStages(StringBuilder sb, BindingInvocationInfo inv) + { + var currentVar = SourceObservableVariable; + + if (inv.HasConversion) + { + var nextVar = inv.HasScheduler ? "__selected" : "bindObs"; + _ = sb.AppendLine( + $" var {nextVar} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({currentVar}, conversionFunc);"); + currentVar = nextVar; + } + + if (inv.HasScheduler) + { + _ = sb.AppendLine( + $" var bindObs = new global::ReactiveUI.Binding.Reactive.ObserveOnObservable<{inv.TargetPropertyTypeFullName}>({currentVar}, scheduler);"); + currentVar = "bindObs"; + } + + return currentVar; + } + + /// Groups binding invocations by source, target, property types, and overload variant for overload generation. /// The fully qualified name of the source (data) type. /// The fully qualified name of the target (UI) type. /// The fully qualified type of the source property. diff --git a/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/BindToCodeGenerator.cs b/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/BindToCodeGenerator.cs index a7ea01d..b4828a8 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/BindToCodeGenerator.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/BindToCodeGenerator.cs @@ -17,9 +17,7 @@ namespace ReactiveUI.Binding.SourceGenerators.CodeGeneration; /// internal static class BindToCodeGenerator { - /// - /// Generates concrete typed overloads and binding methods for BindTo invocations. - /// + /// Generates concrete typed overloads and binding methods for BindTo invocations. /// All detected BindTo invocations. /// The consumer compilation's C# language-feature snapshot (dispatch strategy and nullable support). /// Generated source code string, or null if no invocations. @@ -32,10 +30,10 @@ internal static class BindToCodeGenerator return null; } - var sb = new StringBuilder(invocations.Length * 1_024); + var sb = new StringBuilder(invocations.Length * CodeGeneratorHelpers.PerInvocationBufferCapacity); var supportsCallerArgExpr = features.SupportsCallerArgExpr; CodeGeneratorHelpers.AppendExtensionClassHeader(sb, features); - sb.AppendLine(); + _ = sb.AppendLine(); var groups = GroupByTypeSignature(invocations); @@ -44,7 +42,7 @@ internal static class BindToCodeGenerator var group = groups[g]; GenerateConcreteOverload(sb, group, supportsCallerArgExpr, features.SupportsNullable); - sb.AppendLine(); + _ = sb.AppendLine(); for (var i = 0; i < group.Invocations.Length; i++) { @@ -59,7 +57,7 @@ internal static class BindToCodeGenerator } CodeGeneratorHelpers.AppendExtensionClassFooter(sb); - sb.AppendLine(); + _ = sb.AppendLine(); return sb.ToString(); } @@ -73,12 +71,12 @@ internal static class BindToCodeGenerator internal static List GroupByTypeSignature(ImmutableArray invocations) { var groupMap = new Dictionary>(invocations.Length); - var keySb = new StringBuilder(128); + var keySb = new StringBuilder(CodeGeneratorHelpers.FragmentBufferCapacity); for (var i = 0; i < invocations.Length; i++) { var inv = invocations[i]; - keySb.Clear() + _ = keySb.Clear() .Append(inv.SourceValueTypeFullName).Append('|') .Append(inv.TargetTypeFullName).Append('|') .Append(inv.TargetPropertyTypeFullName).Append('|') @@ -132,16 +130,14 @@ internal static void GenerateConcreteOverload(StringBuilder sb, BindToTypeGroup } } - /// - /// Generates a concrete BindTo overload that dispatches using CallerArgumentExpression. - /// + /// Generates a concrete BindTo overload that dispatches using CallerArgumentExpression. /// The string builder to append to. /// The group of invocations sharing one overload signature. /// Whether the target supports nullable reference types (C# 8+). internal static void GenerateCallerArgExprOverload(StringBuilder sb, BindToTypeGroup group, bool supportsNullable) { var targetPropType = CodeGeneratorHelpers.NullableSelectorLeafType(group.Invocations[0].TargetPropertyPath, supportsNullable); - sb.AppendLine($""" + _ = sb.AppendLine($""" /// /// Concrete typed overload for BindTo of {IObservable}<{group.SourceValueTypeFullName}> to {group.TargetTypeFullName}. /// Uses CallerArgumentExpression for dispatch. @@ -154,7 +150,7 @@ internal static void GenerateCallerArgExprOverload(StringBuilder sb, BindToTypeG AppendExtraParameters(sb, group); - sb.AppendLine($$""" + _ = sb.AppendLine($$""" [{{CallerArgumentExpression}}("property")] string propertyExpression = "", [{{CallerFilePath}}] string callerFilePath = "", [{{CallerLineNumber}}] int callerLineNumber = 0) @@ -174,7 +170,7 @@ internal static void GenerateCallerArgExprOverload(StringBuilder sb, BindToTypeG var condition = CodeGeneratorHelpers.ConditionKeyword(i); var escapedTargetExpr = CodeGeneratorHelpers.EscapeString(inv.TargetExpressionText); - sb.AppendLine($$""" + _ = sb.AppendLine($$""" {{condition}} (propertyExpression == "{{escapedTargetExpr}}") { return __BindTo_{{methodSuffix}}(source, target{{FormatExtraArgs(group)}}); @@ -182,23 +178,21 @@ internal static void GenerateCallerArgExprOverload(StringBuilder sb, BindToTypeG """); } - sb.AppendLine($$""" + _ = sb.AppendLine($$""" throw new {{GeneratedTypeNames.InvalidOperationException}}( "{{NoBindingFoundMessage}}"); } """); } - /// - /// Generates a concrete BindTo overload that dispatches using CallerFilePath + CallerLineNumber. - /// + /// Generates a concrete BindTo overload that dispatches using CallerFilePath + CallerLineNumber. /// The string builder to append to. /// The group of invocations sharing one overload signature. /// Whether the target supports nullable reference types (C# 8+). internal static void GenerateCallerFilePathOverload(StringBuilder sb, BindToTypeGroup group, bool supportsNullable) { var targetPropType = CodeGeneratorHelpers.NullableSelectorLeafType(group.Invocations[0].TargetPropertyPath, supportsNullable); - sb.AppendLine($""" + _ = sb.AppendLine($""" /// /// Concrete typed overload for BindTo of {IObservable}<{group.SourceValueTypeFullName}> to {group.TargetTypeFullName}. /// Uses CallerFilePath + CallerLineNumber for dispatch. @@ -211,7 +205,7 @@ internal static void GenerateCallerFilePathOverload(StringBuilder sb, BindToType AppendExtraParameters(sb, group); - sb.AppendLine($$""" + _ = sb.AppendLine($$""" [{{CallerFilePath}}] string callerFilePath = "", [{{CallerLineNumber}}] int callerLineNumber = 0) { @@ -228,7 +222,7 @@ internal static void GenerateCallerFilePathOverload(StringBuilder sb, BindToType var pathSuffix = CodeGeneratorHelpers.ComputePathSuffix(inv.CallerFilePath); var condition = CodeGeneratorHelpers.ConditionKeyword(i); - sb.AppendLine($$""" + _ = sb.AppendLine($$""" {{condition}} (callerLineNumber == {{inv.CallerLineNumber}} && callerFilePath.EndsWith("{{CodeGeneratorHelpers.EscapeString(pathSuffix)}}", {{OrdinalIgnoreCase}})) { @@ -237,7 +231,7 @@ internal static void GenerateCallerFilePathOverload(StringBuilder sb, BindToType """); } - sb.AppendLine($$""" + _ = sb.AppendLine($$""" throw new {{GeneratedTypeNames.InvalidOperationException}}( "{{NoBindingFoundMessage}}"); } @@ -261,7 +255,7 @@ internal static void GenerateBindToMethod(StringBuilder sb, BindToInvocationInfo // not supply an explicit converter. A conversion hint alone is meaningless for identity assignment. var directAssign = inv.SourceValueTypeFullName == inv.TargetPropertyTypeFullName && !inv.HasConverterOverride; - sb.AppendLine($$""" + _ = sb.AppendLine($$""" private static {{GeneratedTypeNames.IDisposable}} __BindTo_{{suffix}}({{ObservableOf(inv.SourceValueTypeFullName)}} source, {{inv.TargetTypeFullName}} target{{extraParams}}) { // BindTo: observable -> {{targetPathComment}} @@ -269,7 +263,7 @@ internal static void GenerateBindToMethod(StringBuilder sb, BindToInvocationInfo if (directAssign) { - sb.AppendLine($$""" + _ = sb.AppendLine($$""" return {{RxBindingExtensions}}.Subscribe(source, value => { {{targetAccess}} = value; @@ -283,7 +277,7 @@ internal static void GenerateBindToMethod(StringBuilder sb, BindToInvocationInfo var hintArg = inv.HasConversionHint ? "conversionHint" : "null"; var converterArg = inv.HasConverterOverride ? "converterOverride" : "null"; - sb.AppendLine($$""" + _ = sb.AppendLine($$""" return {{RxBindingExtensions}}.Subscribe(source, value => { if ({{RuntimeBindingConverter}}.TryConvert<{{inv.SourceValueTypeFullName}}, {{inv.TargetPropertyTypeFullName}}>(value, {{hintArg}}, {{converterArg}}, out var __converted)) @@ -297,16 +291,14 @@ internal static void GenerateBindToMethod(StringBuilder sb, BindToInvocationInfo } } - /// - /// Appends the conversion-hint and converter-override parameters to the concrete overload signature. - /// + /// Appends the conversion-hint and converter-override parameters to the concrete overload signature. /// The string builder to append to. /// The binding type group. internal static void AppendExtraParameters(StringBuilder sb, BindToTypeGroup group) { if (group.HasConversionHint) { - sb.AppendLine(" object conversionHint,"); + _ = sb.AppendLine(" object conversionHint,"); } if (!group.HasConverterOverride) @@ -314,12 +306,10 @@ internal static void AppendExtraParameters(StringBuilder sb, BindToTypeGroup gro return; } - sb.AppendLine($" {IBindingTypeConverter} converterOverride,"); + _ = sb.AppendLine($" {IBindingTypeConverter} converterOverride,"); } - /// - /// Formats the extra arguments forwarded from the concrete overload to the worker method. - /// + /// Formats the extra arguments forwarded from the concrete overload to the worker method. /// The binding type group. /// An argument list fragment like ", conversionHint, converterOverride", or empty. internal static string FormatExtraArgs(BindToTypeGroup group) @@ -327,20 +317,18 @@ internal static string FormatExtraArgs(BindToTypeGroup group) var sb = new StringBuilder(); if (group.HasConversionHint) { - sb.Append(", conversionHint"); + _ = sb.Append(", conversionHint"); } if (group.HasConverterOverride) { - sb.Append(", converterOverride"); + _ = sb.Append(", converterOverride"); } return sb.ToString(); } - /// - /// Formats the extra parameters for the private worker method signature. - /// + /// Formats the extra parameters for the private worker method signature. /// The binding invocation info. /// A parameter list fragment like ", object conversionHint, ... converterOverride", or empty. internal static string FormatExtraMethodParams(BindToInvocationInfo inv) @@ -348,21 +336,18 @@ internal static string FormatExtraMethodParams(BindToInvocationInfo inv) var sb = new StringBuilder(); if (inv.HasConversionHint) { - sb.Append(", object conversionHint"); + _ = sb.Append(", object conversionHint"); } if (inv.HasConverterOverride) { - sb.Append($", {IBindingTypeConverter} converterOverride"); + _ = sb.Append($", {IBindingTypeConverter} converterOverride"); } return sb.ToString(); } - /// - /// Groups BindTo invocations sharing source value type, target type, target property type, - /// and overload shape. - /// + /// Groups BindTo invocations sharing source value type, target type, target property type, and overload shape. /// The fully qualified observable value type. /// The fully qualified target object type. /// The fully qualified target property type. diff --git a/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/BindTwoWayCodeGenerator.cs b/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/BindTwoWayCodeGenerator.cs index f586130..1c00ad2 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/BindTwoWayCodeGenerator.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/BindTwoWayCodeGenerator.cs @@ -14,9 +14,13 @@ namespace ReactiveUI.Binding.SourceGenerators.CodeGeneration; /// internal static class BindTwoWayCodeGenerator { - /// - /// Generates concrete typed overloads and binding methods for BindTwoWay invocations. - /// + /// Name of the generated local holding the source side observable. + private const string SourceObservableName = "sourceObs"; + + /// Name of the generated local holding the target side observable. + private const string TargetObservableName = "targetObs"; + + /// Generates concrete typed overloads and binding methods for BindTwoWay invocations. /// All detected BindTwoWay invocations. /// All detected class binding info. /// The consumer compilation's C# language-feature snapshot (dispatch strategy and nullable support). @@ -34,7 +38,7 @@ internal static class BindTwoWayCodeGenerator var sb = new StringBuilder(); var supportsCallerArgExpr = features.SupportsCallerArgExpr; CodeGeneratorHelpers.AppendExtensionClassHeader(sb, features); - sb.AppendLine(); + _ = sb.AppendLine(); // Group invocations by (SourceType, TargetType, SourcePropertyType, TargetPropertyType, HasConversion, HasScheduler) var groups = GroupByTypeSignature(invocations); @@ -45,7 +49,7 @@ internal static class BindTwoWayCodeGenerator // Generate the concrete typed extension method overload GenerateConcreteOverload(sb, group, supportsCallerArgExpr, features.SupportsNullable); - sb.AppendLine(); + _ = sb.AppendLine(); // Generate binding methods for (var i = 0; i < group.Invocations.Length; i++) @@ -57,31 +61,29 @@ internal static class BindTwoWayCodeGenerator inv.SourceTypeFullName, inv.CallerFilePath, inv.CallerLineNumber, - inv.SourceExpressionText + "|" + inv.TargetExpressionText); + $"{inv.SourceExpressionText}|{inv.TargetExpressionText}"); GenerateBindTwoWayMethod(sb, inv, sourceClassInfo, targetClassInfo, suffix); } } CodeGeneratorHelpers.AppendExtensionClassFooter(sb); - sb.AppendLine(); + _ = sb.AppendLine(); return sb.ToString(); } - /// - /// Groups BindTwoWay invocations by their type signature for overload generation. - /// + /// Groups BindTwoWay invocations by their type signature for overload generation. /// The BindTwoWay invocations to group. /// A list of grouped invocations sharing the same type signature. internal static List GroupByTypeSignature(ImmutableArray invocations) { var groupMap = new Dictionary>(invocations.Length); - var keySb = new StringBuilder(128); + var keySb = new StringBuilder(CodeGeneratorHelpers.FragmentBufferCapacity); for (var i = 0; i < invocations.Length; i++) { var inv = invocations[i]; - keySb.Clear() + _ = keySb.Clear() .Append(inv.SourceTypeFullName).Append('|') .Append(inv.TargetTypeFullName).Append('|') .Append(inv.SourcePropertyTypeFullName).Append('|') @@ -117,9 +119,7 @@ internal static List GroupByTypeSignature(ImmutableArray - /// Generates the concrete typed overload using the appropriate dispatch strategy. - /// + /// Generates the concrete typed overload using the appropriate dispatch strategy. /// The string builder to append to. /// The binding type group. /// Whether CallerArgumentExpression is available. @@ -140,9 +140,7 @@ internal static void GenerateConcreteOverload( } } - /// - /// Generates the CallerArgumentExpression-based overload for BindTwoWay dispatch. - /// + /// Generates the CallerArgumentExpression-based overload for BindTwoWay dispatch. /// The string builder to append to. /// The binding type group. /// Whether the target supports nullable reference types (C# 8+). @@ -153,7 +151,7 @@ internal static void GenerateCallerArgExprOverload( { var sourcePropType = CodeGeneratorHelpers.NullableSelectorLeafType(group.Invocations[0].SourcePropertyPath, supportsNullable); var targetPropType = CodeGeneratorHelpers.NullableSelectorLeafType(group.Invocations[0].TargetPropertyPath, supportsNullable); - sb.AppendLine($""" + _ = sb.AppendLine($""" /// /// Concrete typed overload for BindTwoWay from {group.SourceTypeFullName} to {group.TargetTypeFullName}. /// Uses CallerArgumentExpression for dispatch. @@ -167,7 +165,7 @@ internal static void GenerateCallerArgExprOverload( AppendExtraParameters(sb, group); - sb.AppendLine(""" + _ = sb.AppendLine(""" [global::System.Runtime.CompilerServices.CallerArgumentExpression("sourceProperty")] string sourcePropertyExpression = "", [global::System.Runtime.CompilerServices.CallerArgumentExpression("targetProperty")] string targetPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", @@ -188,9 +186,9 @@ internal static void GenerateCallerArgExprOverload( inv.SourceTypeFullName, inv.CallerFilePath, inv.CallerLineNumber, - inv.SourceExpressionText + "|" + inv.TargetExpressionText); + $"{inv.SourceExpressionText}|{inv.TargetExpressionText}"); - sb.AppendLine($$""" + _ = sb.AppendLine($$""" {{condition}} (sourcePropertyExpression == "{{escapedSourceExpr}}" && targetPropertyExpression == "{{escapedTargetExpr}}") { @@ -199,16 +197,14 @@ internal static void GenerateCallerArgExprOverload( """); } - sb.AppendLine(""" + _ = sb.AppendLine(""" throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } """); } - /// - /// Generates the CallerFilePath-based overload for BindTwoWay dispatch. - /// + /// Generates the CallerFilePath-based overload for BindTwoWay dispatch. /// The string builder to append to. /// The binding type group. /// Whether the target supports nullable reference types (C# 8+). @@ -219,7 +215,7 @@ internal static void GenerateCallerFilePathOverload( { var sourcePropType = CodeGeneratorHelpers.NullableSelectorLeafType(group.Invocations[0].SourcePropertyPath, supportsNullable); var targetPropType = CodeGeneratorHelpers.NullableSelectorLeafType(group.Invocations[0].TargetPropertyPath, supportsNullable); - sb.AppendLine($""" + _ = sb.AppendLine($""" /// /// Concrete typed overload for BindTwoWay from {group.SourceTypeFullName} to {group.TargetTypeFullName}. /// Uses CallerFilePath + CallerLineNumber for dispatch. @@ -233,7 +229,7 @@ internal static void GenerateCallerFilePathOverload( AppendExtraParameters(sb, group); - sb.AppendLine(""" + _ = sb.AppendLine(""" [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { @@ -248,9 +244,9 @@ internal static void GenerateCallerFilePathOverload( inv.SourceTypeFullName, inv.CallerFilePath, inv.CallerLineNumber, - inv.SourceExpressionText + "|" + inv.TargetExpressionText); + $"{inv.SourceExpressionText}|{inv.TargetExpressionText}"); - sb.AppendLine($$""" + _ = sb.AppendLine($$""" {{condition}} (callerLineNumber == {{inv.CallerLineNumber}} && callerFilePath.EndsWith("{{CodeGeneratorHelpers.EscapeString(pathSuffix)}}", global::System.StringComparison.OrdinalIgnoreCase)) { @@ -259,16 +255,14 @@ internal static void GenerateCallerFilePathOverload( """); } - sb.AppendLine(""" + _ = sb.AppendLine(""" throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } """); } - /// - /// Generates a private BindTwoWay method for a specific invocation. - /// + /// Generates a private BindTwoWay method for a specific invocation. /// The string builder to append to. /// The binding invocation info. /// The source type class binding info. @@ -290,7 +284,7 @@ internal static void GenerateBindTwoWayMethod( var conversionComment = inv.HasConversion ? " (with conversion)" : string.Empty; var schedulerComment = inv.HasScheduler ? " (with scheduler)" : string.Empty; - sb.AppendLine($$""" + _ = sb.AppendLine($$""" private static global::System.IDisposable __BindTwoWay_{{suffix}}({{inv.SourceTypeFullName}} source, {{inv.TargetTypeFullName}} target{{extraParams}}) { // BindTwoWay: {{sourcePathComment}} <-> {{targetPathComment}}{{conversionComment}}{{schedulerComment}} @@ -303,7 +297,7 @@ internal static void GenerateBindTwoWayMethod( inv.SourcePropertyPath, inv.SourcePropertyTypeFullName, sourceClassInfo, - "sourceObs"); + SourceObservableName); ObservationCodeGenerator.EmitInlineObservation( sb, @@ -311,53 +305,28 @@ internal static void GenerateBindTwoWayMethod( inv.TargetPropertyPath, inv.TargetPropertyTypeFullName, targetClassInfo, - "targetObs"); + TargetObservableName); if (inv.HasConversion || inv.HasScheduler) { - var sourceVar = "sourceObs"; - var targetVar = "targetObs"; - - if (inv.HasConversion) - { - var srcNext = inv.HasScheduler ? "__srcSelected" : "sourceBind"; - var tgtNext = inv.HasScheduler ? "__tgtSelected" : "targetBind"; - sb.AppendLine($""" - var {srcNext} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({sourceVar}, sourceToTargetConv); - var {tgtNext} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({targetVar}, targetToSourceConv); - """); - sourceVar = srcNext; - targetVar = tgtNext; - } - - if (inv.HasScheduler) - { - sb.AppendLine($""" - var sourceBind = new global::ReactiveUI.Binding.Reactive.ObserveOnObservable<{inv.TargetPropertyTypeFullName}>({sourceVar}, scheduler); - var targetBind = new global::ReactiveUI.Binding.Reactive.ObserveOnObservable<{inv.SourcePropertyTypeFullName}>({targetVar}, scheduler); - """); - sourceVar = "sourceBind"; - targetVar = "targetBind"; - } + var (sourceVar, targetVar) = EmitConversionAndSchedulerStages(sb, inv); EmitTwoWaySubscription(sb, sourceVar, targetVar, targetAccess, sourceSetAccess); } else { - EmitTwoWaySubscription(sb, "sourceObs", "targetObs", targetAccess, sourceSetAccess); + EmitTwoWaySubscription(sb, SourceObservableName, TargetObservableName, targetAccess, sourceSetAccess); } } - /// - /// Appends extra parameters (converters, scheduler) to the concrete overload signature. - /// + /// Appends extra parameters (converters, scheduler) to the concrete overload signature. /// The string builder to append to. /// The binding type group. internal static void AppendExtraParameters(StringBuilder sb, BindingTypeGroup group) { if (group.HasConversion) { - sb.AppendLine($""" + _ = sb.AppendLine($""" global::System.Func<{group.SourcePropertyTypeFullName}, {group.TargetPropertyTypeFullName}> sourceToTargetConv, global::System.Func<{group.TargetPropertyTypeFullName}, {group.SourcePropertyTypeFullName}> targetToSourceConv, """); @@ -368,12 +337,10 @@ internal static void AppendExtraParameters(StringBuilder sb, BindingTypeGroup gr return; } - sb.AppendLine(" global::System.Reactive.Concurrency.IScheduler scheduler,"); + _ = sb.AppendLine(" global::System.Reactive.Concurrency.IScheduler scheduler,"); } - /// - /// Formats extra arguments (converters, scheduler) for forwarding to the binding method. - /// + /// Formats extra arguments (converters, scheduler) for forwarding to the binding method. /// The binding type group. /// Extra arguments string like ", sourceToTargetConv, targetToSourceConv, scheduler" or empty. internal static string FormatExtraArgs(BindingTypeGroup group) @@ -381,20 +348,18 @@ internal static string FormatExtraArgs(BindingTypeGroup group) var sb = new StringBuilder(); if (group.HasConversion) { - sb.Append(", sourceToTargetConv, targetToSourceConv"); + _ = sb.Append(", sourceToTargetConv, targetToSourceConv"); } if (group.HasScheduler) { - sb.Append(", scheduler"); + _ = sb.Append(", scheduler"); } return sb.ToString(); } - /// - /// Formats extra method parameters for the private binding method signature. - /// + /// Formats extra method parameters for the private binding method signature. /// The binding invocation info. /// Extra parameters string for two-way converter and scheduler parameters. internal static string FormatExtraMethodParams(BindingInvocationInfo inv) @@ -402,7 +367,7 @@ internal static string FormatExtraMethodParams(BindingInvocationInfo inv) var sb = new StringBuilder(); if (inv.HasConversion) { - sb.Append( + _ = sb.Append( $", global::System.Func<{inv.SourcePropertyTypeFullName}, {inv.TargetPropertyTypeFullName}> sourceToTargetConv") .Append( $", global::System.Func<{inv.TargetPropertyTypeFullName}, {inv.SourcePropertyTypeFullName}> targetToSourceConv"); @@ -410,16 +375,53 @@ internal static string FormatExtraMethodParams(BindingInvocationInfo inv) if (inv.HasScheduler) { - sb.Append(", global::System.Reactive.Concurrency.IScheduler scheduler"); + _ = sb.Append(", global::System.Reactive.Concurrency.IScheduler scheduler"); } return sb.ToString(); } /// - /// Emits the two-way subscription and CompositeDisposable2 return block. + /// Emits the conversion and scheduler stages that sit between the raw observations and the + /// subscription, and reports the variable names the subscription should read from. /// /// The string builder to append to. + /// The binding invocation info. + /// The source and target observable variable names after the stages are applied. + private static (string SourceVar, string TargetVar) EmitConversionAndSchedulerStages( + StringBuilder sb, + BindingInvocationInfo inv) + { + var sourceVar = SourceObservableName; + var targetVar = TargetObservableName; + + if (inv.HasConversion) + { + var srcNext = inv.HasScheduler ? "__srcSelected" : "sourceBind"; + var tgtNext = inv.HasScheduler ? "__tgtSelected" : "targetBind"; + _ = sb.AppendLine($""" + var {srcNext} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({sourceVar}, sourceToTargetConv); + var {tgtNext} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({targetVar}, targetToSourceConv); + """); + sourceVar = srcNext; + targetVar = tgtNext; + } + + if (inv.HasScheduler) + { + _ = sb.AppendLine($""" + var sourceBind = new global::ReactiveUI.Binding.Reactive.ObserveOnObservable<{inv.TargetPropertyTypeFullName}>({sourceVar}, scheduler); + var targetBind = new global::ReactiveUI.Binding.Reactive.ObserveOnObservable<{inv.SourcePropertyTypeFullName}>({targetVar}, scheduler); + """); + sourceVar = "sourceBind"; + targetVar = "targetBind"; + } + + return (sourceVar, targetVar); + } + + /// Emits the two-way subscription and CompositeDisposable2 return block. + /// The string builder to append to. /// The source observable variable name to subscribe to. /// The target observable variable name to subscribe to. /// The target property setter access chain. @@ -429,9 +431,7 @@ private static void EmitTwoWaySubscription( string sourceVar, string targetVar, string targetAccess, - string sourceSetAccess) - { - sb.AppendLine($$""" + string sourceSetAccess) => _ = sb.AppendLine($$""" var d1 = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Subscribe({{sourceVar}}, value => { @@ -448,11 +448,8 @@ private static void EmitTwoWaySubscription( } """) .AppendLine(); - } - /// - /// Groups binding invocations by source, target, property types, and overload variant for overload generation. - /// + /// Groups binding invocations by source, target, property types, and overload variant for overload generation. /// The fully qualified name of the source (data) type. /// The fully qualified name of the target (UI) type. /// The fully qualified type of the source property. diff --git a/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/CodeGeneratorHelpers.cs b/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/CodeGeneratorHelpers.cs index 0b4af0e..c3af714 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/CodeGeneratorHelpers.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/CodeGeneratorHelpers.cs @@ -8,30 +8,31 @@ namespace ReactiveUI.Binding.SourceGenerators.CodeGeneration; -/// -/// Shared utility methods for code generation: property path building, string escaping, -/// and class info lookup. -/// +/// Shared utility methods for code generation: property path building, string escaping, and class info lookup. internal static class CodeGeneratorHelpers { - /// - /// The initial seed value for the polynomial hash used by . - /// + /// Buffer capacity to reserve per invocation when building a generated source file. + internal const int PerInvocationBufferCapacity = 1_024; + + /// Buffer capacity for a dispatch key or other short generated fragment. + internal const int FragmentBufferCapacity = 128; + + /// Buffer capacity to reserve per property-path segment when building an access chain. + private const int PerPathSegmentCapacity = 16; + + /// Extra buffer capacity for the escaping a string literal adds. + private const int EscapeOverheadCapacity = 4; + + /// The initial seed value for the polynomial hash used by . private const long HashSeed = 17L; - /// - /// The multiplier applied at each step of the polynomial hash used by . - /// + /// The multiplier applied at each step of the polynomial hash used by . private const long HashMultiplier = 31L; - /// - /// The FNV-1a 32-bit offset basis used by . - /// + /// The FNV-1a 32-bit offset basis used by . private const uint FnvOffsetBasis = 2_166_136_261; - /// - /// The FNV-1a 32-bit prime used by . - /// + /// The FNV-1a 32-bit prime used by . private const int FnvPrime = 16_777_619; /// @@ -48,13 +49,11 @@ internal static string NullableSelectorLeafType(EquatableArray - /// Builds a dotted property access chain from a root variable and property path segments. - /// + /// Builds a dotted property access chain from a root variable and property path segments. /// The root variable name (e.g., "obj", "source"). /// The property path segments. /// A dotted access chain like "obj.Address.City". @@ -65,37 +64,31 @@ internal static string BuildPropertyAccessChain(string root, EquatableArray - /// Builds a property access expression for use in a lambda body. - /// + /// Builds a property access expression for use in a lambda body. /// The lambda parameter name. /// The property path segments. /// A dotted access chain like "x.Address.City". internal static string BuildPropertyAccessLambda(string param, EquatableArray path) => BuildPropertyAccessChain(param, path); - /// - /// Builds a property setter chain for assignment (e.g., target.Header.Title). - /// + /// Builds a property setter chain for assignment (e.g., target.Header.Title). /// The root variable name. /// The property path segments. /// A dotted access chain suitable for the left side of an assignment. internal static string BuildPropertySetterChain(string root, EquatableArray path) => BuildPropertyAccessChain(root, path); - /// - /// Builds a human-readable dotted property path string for comments. - /// + /// Builds a human-readable dotted property path string for comments. /// The property path segments. /// A dotted string like "Address.City". internal static string BuildPropertyPathString(EquatableArray path) @@ -105,15 +98,15 @@ internal static string BuildPropertyPathString(EquatableArray 0) { - sb.Append('.'); + _ = sb.Append('.'); } - sb.Append(path[i].PropertyName); + _ = sb.Append(path[i].PropertyName); } return sb.ToString(); @@ -146,17 +139,10 @@ internal static string ComputePathSuffix(string filePath) } var secondLastSlash = filePath.LastIndexOf('/', lastSlash - 1); - if (secondLastSlash < 0) - { - return filePath; - } - - return filePath.Substring(secondLastSlash + 1); + return secondLastSlash < 0 ? filePath : filePath.Substring(secondLastSlash + 1); } - /// - /// Escapes a string for embedding in a C# string literal. - /// + /// Escapes a string for embedding in a C# string literal. /// The string to escape. /// The escaped string. internal static string EscapeString(string value) @@ -178,21 +164,21 @@ internal static string EscapeString(string value) return value; } - var sb = new StringBuilder(value.Length + 4); + var sb = new StringBuilder(value.Length + EscapeOverheadCapacity); for (var i = 0; i < value.Length; i++) { var c = value[i]; if (c == '\\') { - sb.Append("\\\\"); + _ = sb.Append("\\\\"); } else if (c == '"') { - sb.Append("\\\""); + _ = sb.Append("\\\""); } else { - sb.Append(c); + _ = sb.Append(c); } } @@ -210,19 +196,12 @@ internal static string EscapeString(string value) internal static string NormalizeLambdaText(string expressionText) { const string StaticPrefix = "static "; - if (expressionText.Length > StaticPrefix.Length + return expressionText.Length > StaticPrefix.Length && expressionText[0] == 's' - && expressionText.StartsWith(StaticPrefix, StringComparison.Ordinal)) - { - return expressionText.Substring(StaticPrefix.Length); - } - - return expressionText; + && expressionText.StartsWith(StaticPrefix, StringComparison.Ordinal) ? expressionText.Substring(StaticPrefix.Length) : expressionText; } - /// - /// Appends the standard auto-generated file header and opens the extension partial class. - /// + /// Appends the standard auto-generated file header and opens the extension partial class. /// The string builder to append to. /// /// The consumer compilation's language-feature and generation-option snapshot. Controls whether the @@ -234,10 +213,10 @@ internal static void AppendExtensionClassHeader(StringBuilder sb, LanguageFeatur AppendGeneratedFileMarkers(sb, features.EmitGeneratedCodeMarkers); if (features.SupportsNullable) { - sb.AppendLine("#nullable enable"); + _ = sb.AppendLine("#nullable enable"); } - sb.Append(""" + _ = sb.Append(""" using System; @@ -262,13 +241,11 @@ internal static void AppendGeneratedFileMarkers(StringBuilder sb, bool emitGener return; } - sb.AppendLine("// ") + _ = sb.AppendLine("// ") .AppendLine("#pragma warning disable"); } - /// - /// Appends the closing braces for the extension partial class and namespace. - /// + /// Appends the closing braces for the extension partial class and namespace. /// The string builder to append to. internal static void AppendExtensionClassFooter(StringBuilder sb) => sb.Append(""" @@ -304,9 +281,7 @@ internal static string ComputeStableMethodSuffix( } } - /// - /// Finds a by fully qualified type name. - /// + /// Finds a by fully qualified type name. /// All detected class binding infos. /// The fully qualified name to match. /// The matching class info, or null if not found. @@ -325,15 +300,12 @@ internal static string ComputeStableMethodSuffix( return null; } - /// - /// Computes a deterministic hash for a string using FNV-1a. - /// Unlike , this is stable across processes and .NET versions. - /// + /// Computes a deterministic hash for a string using FNV-1a. Unlike , this is stable across processes and .NET versions. /// The string to hash. /// A deterministic 32-bit hash code. internal static int StableStringHash(string s) { - if (s == null) + if (s is null) { return 0; } diff --git a/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/GeneratedTypeNames.cs b/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/GeneratedTypeNames.cs index 4d7f61f..c3a5821 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/GeneratedTypeNames.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/GeneratedTypeNames.cs @@ -24,19 +24,19 @@ internal static class GeneratedTypeNames /// System.Linq.Expressions.Expression (open generic; use ). internal const string Expression = "global::System.Linq.Expressions.Expression"; - /// System.IDisposable. + /// The fully qualified name of System.IDisposable. internal const string IDisposable = "global::System.IDisposable"; - /// System.InvalidOperationException. + /// The fully qualified name of System.InvalidOperationException. internal const string InvalidOperationException = "global::System.InvalidOperationException"; - /// System.StringComparison.OrdinalIgnoreCase. + /// The fully qualified name of the StringComparison.OrdinalIgnoreCase member. internal const string OrdinalIgnoreCase = "global::System.StringComparison.OrdinalIgnoreCase"; - /// System.ComponentModel.INotifyPropertyChanging. + /// The fully qualified name of System.ComponentModel.INotifyPropertyChanging. internal const string INotifyPropertyChanging = "global::System.ComponentModel.INotifyPropertyChanging"; - /// System.ComponentModel.INotifyPropertyChanged. + /// The fully qualified name of System.ComponentModel.INotifyPropertyChanged. internal const string INotifyPropertyChanged = "global::System.ComponentModel.INotifyPropertyChanged"; /// The [CallerArgumentExpression] attribute type. @@ -51,19 +51,19 @@ internal static class GeneratedTypeNames /// ReactiveUI.Binding.IInteraction (open generic). internal const string IInteraction = "global::ReactiveUI.Binding.IInteraction"; - /// ReactiveUI.Binding.IBindingTypeConverter. + /// The fully qualified name of ReactiveUI.Binding.IBindingTypeConverter. internal const string IBindingTypeConverter = "global::ReactiveUI.Binding.IBindingTypeConverter"; /// The ReactiveUI.Binding.Observables namespace prefix (no trailing dot). internal const string Observables = "global::ReactiveUI.Binding.Observables"; - /// ReactiveUI.Binding.Observables.RxBindingExtensions. + /// The fully qualified name of ReactiveUI.Binding.Observables.RxBindingExtensions. internal const string RxBindingExtensions = "global::ReactiveUI.Binding.Observables.RxBindingExtensions"; - /// ReactiveUI.Binding.Fallback.RuntimeBindingConverter. + /// The fully qualified name of ReactiveUI.Binding.Fallback.RuntimeBindingConverter. internal const string RuntimeBindingConverter = "global::ReactiveUI.Binding.Fallback.RuntimeBindingConverter"; - /// ReactiveUI.Binding.Fallback.ObservationAffinityChecker. + /// The fully qualified name of ReactiveUI.Binding.Fallback.ObservationAffinityChecker. internal const string ObservationAffinityChecker = "global::ReactiveUI.Binding.Fallback.ObservationAffinityChecker"; /// diff --git a/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/ObservationCodeGenerator.cs b/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/ObservationCodeGenerator.cs index 2676423..44864b2 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/ObservationCodeGenerator.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/ObservationCodeGenerator.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for full license information. using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; using System.Text; using ReactiveUI.Binding.SourceGenerators.Models; using ReactiveUI.Binding.SourceGenerators.Plugins; @@ -43,10 +42,6 @@ internal static string GetTypeCastName(ClassBindingInfo? classInfo) => /// /// The class binding info, or null. /// if INPC observation is supported. - [SuppressMessage( - "Minor Code Smell", - "S100:Methods and properties should be named in PascalCase", - Justification = "INPC abbreviates INotifyPropertyChanged, an established acronym matching the ReactiveUI domain terminology.")] internal static bool IsINPC(ClassBindingInfo? classInfo) => classInfo is not null && (classInfo.ImplementsIReactiveObject || classInfo.ImplementsINPC); @@ -58,16 +53,10 @@ internal static bool IsINPC(ClassBindingInfo? classInfo) => /// /// The class binding info, or null. /// if INPChanging observation is supported. - [SuppressMessage( - "Minor Code Smell", - "S100:Methods and properties should be named in PascalCase", - Justification = "INPC abbreviates INotifyPropertyChanged, an established acronym matching the ReactiveUI domain terminology.")] internal static bool IsINPChanging(ClassBindingInfo? classInfo) => classInfo is not null && (classInfo.ImplementsIReactiveObject || classInfo.ImplementsINPChanging); - /// - /// Generates concrete typed overloads and observation methods for property observation invocations. - /// + /// Generates concrete typed overloads and observation methods for property observation invocations. /// All detected invocations. /// All detected class binding info for type mechanism lookup. /// The consumer compilation's C# language-feature snapshot (dispatch strategy and nullable support). @@ -84,10 +73,10 @@ internal static bool IsINPChanging(ClassBindingInfo? classInfo) => return null; } - var sb = new StringBuilder(invocations.Length * 1_024); + var sb = new StringBuilder(invocations.Length * CodeGeneratorHelpers.PerInvocationBufferCapacity); var supportsCallerArgExpr = features.SupportsCallerArgExpr; CodeGeneratorHelpers.AppendExtensionClassHeader(sb, features); - sb.AppendLine(); + _ = sb.AppendLine(); // Track which plugins with helper classes are used, so we emit them once var usedPluginKinds = new HashSet(); @@ -103,14 +92,12 @@ internal static bool IsINPChanging(ClassBindingInfo? classInfo) => EmitUsedHelperClasses(sb, usedPluginKinds); CodeGeneratorHelpers.AppendExtensionClassFooter(sb); - sb.AppendLine(); + _ = sb.AppendLine(); return sb.ToString(); } - /// - /// Generates an observation method for a single invocation. - /// + /// Generates an observation method for a single invocation. /// The string builder to append to. /// The invocation info. /// The class binding info for the source type, or null. @@ -125,9 +112,9 @@ internal static void GenerateObservationMethod( bool isBeforeChange, string prefix) { - var selectorParam = inv.HasSelector ? ", " + GetSelectorType(inv) + " selector" : string.Empty; + var selectorParam = inv.HasSelector ? $", {GetSelectorType(inv)} selector" : string.Empty; - sb.AppendLine($$""" + _ = sb.AppendLine($$""" private static global::System.IObservable<{{inv.ReturnTypeFullName}}> __{{prefix}}_{{suffix}}({{inv.SourceTypeFullName}} obj{{selectorParam}}) { """); @@ -147,9 +134,9 @@ internal static void GenerateObservationMethod( if (inv.HasSelector) { - sb.Append(" return global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select("); + _ = sb.Append(" return global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select("); GenerateShallowPathObservation(sb, path, classInfo, isBeforeChange); - sb.AppendLine(", selector);"); + _ = sb.AppendLine(", selector);"); } else { @@ -168,14 +155,12 @@ internal static void GenerateObservationMethod( GenerateMultiPropertyObservation(sb, inv, classInfo, isBeforeChange); } - sb.AppendLine() + _ = sb.AppendLine() .AppendLine(" }") .AppendLine(); } - /// - /// Gets the Func type signature for a selector parameter. - /// + /// Gets the Func type signature for a selector parameter. /// The invocation info containing property path and return type information. /// A fully qualified Func type string like global::System.Func<T1, T2, TReturn>. internal static string GetSelectorType(InvocationInfo inv) @@ -184,10 +169,10 @@ internal static string GetSelectorType(InvocationInfo inv) for (var i = 0; i < inv.PropertyPaths.Length; i++) { var path = inv.PropertyPaths[i]; - sb.Append(path[path.Length - 1].PropertyTypeFullName).Append(", "); + _ = sb.Append(path[path.Length - 1].PropertyTypeFullName).Append(", "); } - sb.Append(inv.ReturnTypeFullName).Append('>'); + _ = sb.Append(inv.ReturnTypeFullName).Append('>'); return sb.ToString(); } @@ -212,7 +197,7 @@ internal static void GenerateMultiPropertyObservation( for (var i = 0; i < inv.PropertyPaths.Length; i++) { var path = inv.PropertyPaths[i]; - var varName = "__propObs" + i; + var varName = $"__propObs{i}"; if (path.Length > 1) { @@ -224,23 +209,23 @@ internal static void GenerateMultiPropertyObservation( } // Blank line between variable declarations for readability - sb.AppendLine() + _ = sb.AppendLine() .AppendLine(); } - sb.AppendLine(" return global::ReactiveUI.Binding.Observables.CombineLatestObservable.Create("); + _ = sb.AppendLine(" return global::ReactiveUI.Binding.Observables.CombineLatestObservable.Create("); for (var i = 0; i < inv.PropertyPaths.Length; i++) { - sb.Append(" __propObs").Append(i); + _ = sb.Append(" __propObs").Append(i); if (i < inv.PropertyPaths.Length - 1) { - sb.AppendLine(","); + _ = sb.AppendLine(","); } } if (inv.HasSelector) { - sb.AppendLine(",") + _ = sb.AppendLine(",") .Append(" selector);"); } else @@ -273,15 +258,15 @@ internal static void GenerateShallowPathObservation( } else if (IsINPChanging(classInfo) && isBeforeChange) { - sb.Append( - $"new global::ReactiveUI.Binding.Observables.PropertyChangingObservable<{segment.PropertyTypeFullName}>((" + - $"""global::System.ComponentModel.INotifyPropertyChanging)obj, "{segment.PropertyName}", (global::System.ComponentModel.INotifyPropertyChanging __o) => (""" + - $"({GetTypeCastName(classInfo)})__o).{segment.PropertyName})"); + _ = sb + .Append($"new global::ReactiveUI.Binding.Observables.PropertyChangingObservable<{segment.PropertyTypeFullName}>((") + .Append($"""global::System.ComponentModel.INotifyPropertyChanging)obj, "{segment.PropertyName}", (global::System.ComponentModel.INotifyPropertyChanging __o) => (""") + .Append($"({GetTypeCastName(classInfo)})__o).{segment.PropertyName})"); } else { - var propertyAccess = "obj." + segment.PropertyName; - sb.Append( + var propertyAccess = $"obj.{segment.PropertyName}"; + _ = sb.Append( $"new global::ReactiveUI.Binding.Observables.ReturnObservable<{segment.PropertyTypeFullName}>({propertyAccess})"); } } @@ -317,7 +302,7 @@ internal static void GenerateShallowObservableVariable( } else if (IsINPChanging(classInfo) && isBeforeChange) { - sb.Append($""" + _ = sb.Append($""" var {varName} = new global::ReactiveUI.Binding.Observables.PropertyChangingObservable<{segment.PropertyTypeFullName}>( (global::System.ComponentModel.INotifyPropertyChanging)obj, "{segment.PropertyName}", @@ -326,8 +311,8 @@ internal static void GenerateShallowObservableVariable( } else { - var propertyAccess = "obj." + segment.PropertyName; - sb.Append( + var propertyAccess = $"obj.{segment.PropertyName}"; + _ = sb.Append( $" var {varName} = new global::ReactiveUI.Binding.Observables.ReturnObservable<{segment.PropertyTypeFullName}>({propertyAccess});"); } } @@ -350,7 +335,7 @@ internal static void GenerateDeepChainVariable( { // First segment: observe root object for first property var seg0 = path[0]; - var obs0Var = varName + "_s0"; + var obs0Var = $"{varName}_s0"; var rootPlugin = classInfo is not null ? ObservationPluginRegistry.GetBestPlugin(classInfo) : null; if (rootPlugin is not null) @@ -359,7 +344,7 @@ internal static void GenerateDeepChainVariable( } else if (IsINPChanging(classInfo) && isBeforeChange) { - sb.AppendLine($""" + _ = sb.AppendLine($""" var {obs0Var} = (global::System.IObservable<{seg0.PropertyTypeFullName}>)new global::ReactiveUI.Binding.Observables.PropertyChangingObservable<{seg0.PropertyTypeFullName}>( (global::System.ComponentModel.INotifyPropertyChanging)obj, "{seg0.PropertyName}", @@ -368,60 +353,17 @@ internal static void GenerateDeepChainVariable( } else { - sb.AppendLine( - $" var {obs0Var} = (global::System.IObservable<{seg0.PropertyTypeFullName}>" + - $")new global::ReactiveUI.Binding.Observables.ReturnObservable<{seg0.PropertyTypeFullName}>(obj.{seg0.PropertyName});"); + _ = sb + .Append($" var {obs0Var} = (global::System.IObservable<{seg0.PropertyTypeFullName}>") + .AppendLine($")new global::ReactiveUI.Binding.Observables.ReturnObservable<{seg0.PropertyTypeFullName}>(obj.{seg0.PropertyName});"); } - // Chain remaining segments using Select + Switch for reactive re-subscription - for (var s = 1; s < path.Length; s++) - { - var seg = path[s]; - var prevObsVar = varName + "_s" + (s - 1); - var curObsVar = varName + "_s" + s; - var lambdaParam = varName + "_p" + s; - - // All plugins emit generic INPC-based PropertyObservable for inner segments, - // so reusing the root plugin is safe regardless of the inner segment's declaring type. - var innerPlugin = rootPlugin; - - if (innerPlugin is not null) - { - innerPlugin.EmitDeepChainInnerSegment(sb, prevObsVar, curObsVar, lambdaParam, seg, isBeforeChange); - } - else if (IsINPChanging(classInfo) && isBeforeChange) - { - var segType = seg.PropertyTypeFullName; - sb.AppendLine() - .AppendLine($""" - var {curObsVar} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Switch( - global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({prevObsVar}, - {lambdaParam} => {lambdaParam} != null - ? (global::System.IObservable<{segType}>)new global::ReactiveUI.Binding.Observables.PropertyChangingObservable<{segType}>( - (global::System.ComponentModel.INotifyPropertyChanging){lambdaParam}, - "{seg.PropertyName}", - (global::System.ComponentModel.INotifyPropertyChanging __o) => (({seg.DeclaringTypeFullName})__o).{seg.PropertyName}) - : (global::System.IObservable<{segType}>)new global::ReactiveUI.Binding.Observables.ReturnObservable<{segType}>(default({segType})))); - """); - } - else - { - var segType = seg.PropertyTypeFullName; - var declType = seg.DeclaringTypeFullName; - sb.AppendLine() - .AppendLine($""" - var {curObsVar} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Switch( - global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({prevObsVar}, - {lambdaParam} => (global::System.IObservable<{segType}>)new global::ReactiveUI.Binding.Observables.ReturnObservable<{segType}>( - {lambdaParam} != null ? (({declType}){lambdaParam}).{seg.PropertyName} : default({segType})))); - """); - } - } + EmitDeepChainInnerSegments(sb, path, classInfo, rootPlugin, isBeforeChange, varName); - var lastObsVar = varName + "_s" + (path.Length - 1); - sb.AppendLine(isBeforeChange - ? $" var {varName} = {lastObsVar};" - : $" var {varName} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.DistinctUntilChanged({lastObsVar});"); + var lastObsVar = $"{varName}_s{path.Length - 1}"; + _ = sb.AppendLine(isBeforeChange + ? $" var {varName} = {lastObsVar};" + : $" var {varName} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.DistinctUntilChanged({lastObsVar});"); } /// @@ -433,12 +375,12 @@ internal static void GenerateDeepChainVariable( internal static List GroupByTypeSignature(ImmutableArray invocations) { var groupMap = new Dictionary>(invocations.Length); - var keySb = new StringBuilder(128); + var keySb = new StringBuilder(CodeGeneratorHelpers.FragmentBufferCapacity); for (var i = 0; i < invocations.Length; i++) { var inv = invocations[i]; - keySb.Clear() + _ = keySb.Clear() .Append(inv.SourceTypeFullName).Append('|') .Append(inv.ReturnTypeFullName).Append('|') .Append(inv.PropertyPaths.Length).Append('|') @@ -446,7 +388,7 @@ internal static List GroupByTypeSignature(ImmutableArray @@ -546,7 +488,7 @@ internal static void EmitAffinityCheck( { var isBeforeChange = methodPrefix == "WhenChanging"; - sb.AppendLine( + _ = sb.AppendLine( " // Allow user-registered plugins with higher affinity to override generated observation") .AppendLine( $" if ({ObservationAffinityChecker}.HasHigherAffinityPlugin(typeof({first.SourceTypeFullName}), {generatedAffinity}, {(isBeforeChange ? "true" : "false")}))") @@ -554,7 +496,7 @@ internal static void EmitAffinityCheck( EmitAffinityFallbackReturn(sb, first, methodPrefix, propCount, hasSelector); - sb.AppendLine(" }") + _ = sb.AppendLine(" }") .AppendLine(); } @@ -581,20 +523,20 @@ internal static void EmitAffinityFallbackReturn( var propArgs = new StringBuilder(); for (var i = 0; i < propCount; i++) { - propArgs.Append($", property{i + 1}"); + _ = propArgs.Append($", property{i + 1}"); } if (!hasSelector) { // No selector: direct call to RuntimeObservationFallback - sb.AppendLine( + _ = sb.AppendLine( $" return global::ReactiveUI.Binding.Fallback.RuntimeObservationFallback.{fallbackMethod}(objectToMonitor{propArgs});"); } else if (propCount == 1) { // Single property with selector: wrap fallback with SelectObservable var propType = first.PropertyPaths[0][first.PropertyPaths[0].Length - 1].PropertyTypeFullName; - sb.AppendLine( + _ = sb.AppendLine( $" return new global::ReactiveUI.Binding.Observables.SelectObservable<{propType}, {first.ReturnTypeFullName}>(") .AppendLine( $" global::ReactiveUI.Binding.Fallback.RuntimeObservationFallback.{fallbackMethod}(objectToMonitor{propArgs}),") @@ -607,27 +549,27 @@ internal static void EmitAffinityFallbackReturn( for (var i = 0; i < propCount; i++) { var path = first.PropertyPaths[i]; - tupleType.Append(path[path.Length - 1].PropertyTypeFullName); + _ = tupleType.Append(path[path.Length - 1].PropertyTypeFullName); if (i < propCount - 1) { - tupleType.Append(", "); + _ = tupleType.Append(", "); } } - tupleType.Append('>'); + _ = tupleType.Append('>'); // Build the selector decomposition lambda: __t => selector(__t.Item1, __t.Item2, ...) var selectorArgs = new StringBuilder(); for (var i = 0; i < propCount; i++) { - selectorArgs.Append("__t.Item").Append(i + 1); + _ = selectorArgs.Append("__t.Item").Append(i + 1); if (i < propCount - 1) { - selectorArgs.Append(", "); + _ = selectorArgs.Append(", "); } } - sb.AppendLine( + _ = sb.AppendLine( $" return new global::ReactiveUI.Binding.Observables.SelectObservable<{tupleType}, {first.ReturnTypeFullName}>(") .AppendLine( $" global::ReactiveUI.Binding.Fallback.RuntimeObservationFallback.{fallbackMethod}(objectToMonitor{propArgs}),") @@ -635,9 +577,7 @@ internal static void EmitAffinityFallbackReturn( } } - /// - /// Generates a single-property observation method body using plugin dispatch. - /// + /// Generates a single-property observation method body using plugin dispatch. /// The string builder to append to. /// The invocation info. /// The class binding info for the source type, or null. @@ -657,14 +597,14 @@ internal static void GenerateSinglePropertyObservation( if (plugin is not null) { var segment = inv.PropertyPaths[0][0]; - sb.Append(" return "); + _ = sb.Append(" return "); plugin.EmitShallowObservation(sb, "obj", segment, GetTypeCastName(classInfo), isBeforeChange, true); - sb.Append(';'); + _ = sb.Append(';'); } else if (IsINPChanging(classInfo) && isBeforeChange) { // INPChanging-only type (no INPC, no IReactiveObject) — can observe before-change - sb.Append($""" + _ = sb.Append($""" return new global::ReactiveUI.Binding.Observables.PropertyChangingObservable<{inv.ReturnTypeFullName}>( (global::System.ComponentModel.INotifyPropertyChanging)obj, "{propertyName}", @@ -673,15 +613,12 @@ internal static void GenerateSinglePropertyObservation( } else { - sb.Append( + _ = sb.Append( $" return new global::ReactiveUI.Binding.Observables.ReturnObservable<{inv.ReturnTypeFullName}>({propertyAccess});"); } } - /// - /// Generates a deep chain observation method body using plugin dispatch - /// for the root segment and inner segments. - /// + /// Generates a deep chain observation method body using plugin dispatch for the root segment and inner segments. /// The string builder to append to. /// The invocation info. /// The class binding info for the source type, or null. @@ -703,7 +640,7 @@ internal static void GenerateDeepChainObservation( } else if (IsINPChanging(classInfo) && isBeforeChange) { - sb.AppendLine($""" + _ = sb.AppendLine($""" var __obs0 = (global::System.IObservable<{seg0.PropertyTypeFullName}>)new global::ReactiveUI.Binding.Observables.PropertyChangingObservable<{seg0.PropertyTypeFullName}>( (global::System.ComponentModel.INotifyPropertyChanging)obj, "{seg0.PropertyName}", @@ -712,58 +649,15 @@ internal static void GenerateDeepChainObservation( } else { - sb.AppendLine( - $" var __obs0 = (global::System.IObservable<{seg0.PropertyTypeFullName}>" + - $")new global::ReactiveUI.Binding.Observables.ReturnObservable<{seg0.PropertyTypeFullName}>(obj.{seg0.PropertyName});"); + _ = sb + .Append($" var __obs0 = (global::System.IObservable<{seg0.PropertyTypeFullName}>") + .AppendLine($")new global::ReactiveUI.Binding.Observables.ReturnObservable<{seg0.PropertyTypeFullName}>(obj.{seg0.PropertyName});"); } - // Chain remaining segments using Select + Switch for reactive re-subscription - for (var s = 1; s < path.Length; s++) - { - var seg = path[s]; - var prevVar = $"__obs{s - 1}"; - var curVar = $"__obs{s}"; - var lambdaParam = $"__parent{s}"; - - // All plugins emit generic INPC-based PropertyObservable for inner segments, - // so reusing the root plugin is safe regardless of the inner segment's declaring type. - var innerPlugin = rootPlugin; - - if (innerPlugin is not null) - { - innerPlugin.EmitDeepChainInnerSegment(sb, prevVar, curVar, lambdaParam, seg, isBeforeChange); - } - else if (IsINPChanging(classInfo) && isBeforeChange) - { - var segType = seg.PropertyTypeFullName; - sb.AppendLine() - .AppendLine($""" - var {curVar} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Switch( - global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({prevVar}, - {lambdaParam} => {lambdaParam} != null - ? (global::System.IObservable<{segType}>)new global::ReactiveUI.Binding.Observables.PropertyChangingObservable<{segType}>( - (global::System.ComponentModel.INotifyPropertyChanging){lambdaParam}, - "{seg.PropertyName}", - (global::System.ComponentModel.INotifyPropertyChanging __o) => (({seg.DeclaringTypeFullName})__o).{seg.PropertyName}) - : (global::System.IObservable<{segType}>)new global::ReactiveUI.Binding.Observables.ReturnObservable<{segType}>(default({segType})))); - """); - } - else - { - var segType = seg.PropertyTypeFullName; - var declType = seg.DeclaringTypeFullName; - sb.AppendLine() - .AppendLine($""" - var {curVar} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Switch( - global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({prevVar}, - {lambdaParam} => (global::System.IObservable<{segType}>)new global::ReactiveUI.Binding.Observables.ReturnObservable<{segType}>( - {lambdaParam} != null ? (({declType}){lambdaParam}).{seg.PropertyName} : default({segType})))); - """); - } - } + EmitObservationChainInnerSegments(sb, path, classInfo, rootPlugin, isBeforeChange); var lastObs = $"__obs{path.Length - 1}"; - sb.Append(isBeforeChange + _ = sb.Append(isBeforeChange ? $" return {lastObs};" : $" return global::ReactiveUI.Binding.Observables.RxBindingExtensions.DistinctUntilChanged({lastObs});"); } @@ -800,63 +694,194 @@ internal static void EmitInlineObservation( else { var propertyAccess = $"{rootVar}.{segment.PropertyName}"; - sb.AppendLine( + _ = sb.AppendLine( $" var {variableName} = new global::ReactiveUI.Binding.Observables.ReturnObservable<{propertyTypeFullName}>({propertyAccess});"); } } else { - // Deep chain: emit Select/Switch pattern using plugin dispatch - var seg0 = propertyPath[0]; + EmitInlineDeepChain(sb, rootVar, propertyPath, classInfo, plugin, variableName); + } + } - if (plugin is not null) + /// + /// Chains the segments after the root for the standalone observation method, which names its + /// stages __obsN rather than deriving them from a caller-supplied prefix. + /// + /// The string builder to append to. + /// The property path being observed. + /// The root type's binding info, when known. + /// + /// The root type's observation plugin. Every plugin emits the same generic notification observable + /// for inner segments, so reusing the root's plugin is safe whatever the segment declares. + /// + /// Whether before-change notifications are being observed. + private static void EmitObservationChainInnerSegments( + StringBuilder sb, + EquatableArray path, + ClassBindingInfo? classInfo, + IObservationPlugin? rootPlugin, + bool isBeforeChange) + { + for (var s = 1; s < path.Length; s++) + { + var seg = path[s]; + var prevVar = $"__obs{s - 1}"; + var curVar = $"__obs{s}"; + var lambdaParam = $"__parent{s}"; + var segType = seg.PropertyTypeFullName; + + if (rootPlugin is not null) { - plugin.EmitDeepChainRootSegment( - sb, - rootVar, - seg0, - GetTypeCastName(classInfo), - false, - $"__{variableName}_s0"); + rootPlugin.EmitDeepChainInnerSegment(sb, prevVar, curVar, lambdaParam, seg, isBeforeChange); } - else + else if (IsINPChanging(classInfo) && isBeforeChange) { - sb.AppendLine( - $" var __{variableName}_s0 = (global::System.IObservable<{seg0.PropertyTypeFullName}>" + - $")new global::ReactiveUI.Binding.Observables.ReturnObservable<{seg0.PropertyTypeFullName}>({rootVar}.{seg0.PropertyName});"); + _ = sb.AppendLine() + .AppendLine($""" + var {curVar} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Switch( + global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({prevVar}, + {lambdaParam} => {lambdaParam} != null + ? (global::System.IObservable<{segType}>)new global::ReactiveUI.Binding.Observables.PropertyChangingObservable<{segType}>( + (global::System.ComponentModel.INotifyPropertyChanging){lambdaParam}, + "{seg.PropertyName}", + (global::System.ComponentModel.INotifyPropertyChanging __o) => (({seg.DeclaringTypeFullName})__o).{seg.PropertyName}) + : (global::System.IObservable<{segType}>)new global::ReactiveUI.Binding.Observables.ReturnObservable<{segType}>(default({segType})))); + """); } - - for (var s = 1; s < propertyPath.Length; s++) + else { - var seg = propertyPath[s]; - var prevVar = $"__{variableName}_s{s - 1}"; - var curVar = $"__{variableName}_s{s}"; - var lambdaParam = $"__p{s}"; - - if (plugin is not null) - { - plugin.EmitDeepChainInnerSegment(sb, prevVar, curVar, lambdaParam, seg, false); - } - else - { - var segType = seg.PropertyTypeFullName; - var declType = seg.DeclaringTypeFullName; - sb.AppendLine() - .AppendLine($""" + _ = sb.AppendLine() + .AppendLine($""" var {curVar} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Switch( global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({prevVar}, {lambdaParam} => (global::System.IObservable<{segType}>)new global::ReactiveUI.Binding.Observables.ReturnObservable<{segType}>( - {lambdaParam} != null ? (({declType}){lambdaParam}).{seg.PropertyName} : default({segType})))); - """); - } + {lambdaParam} != null ? (({seg.DeclaringTypeFullName}){lambdaParam}).{seg.PropertyName} : default({segType})))); + """); } + } + } + + /// + /// Chains the segments after the root with Select + Switch, so the observation re-subscribes when + /// an intermediate value changes. + /// + /// The string builder to append to. + /// The property path being observed. + /// The root type's binding info, when known. + /// + /// The root type's observation plugin. Every plugin emits the same generic notification observable + /// for inner segments, so reusing the root's plugin is safe whatever the segment declares. + /// + /// Whether before-change notifications are being observed. + /// The variable-name prefix for the emitted stages. + private static void EmitDeepChainInnerSegments( + StringBuilder sb, + EquatableArray path, + ClassBindingInfo? classInfo, + IObservationPlugin? rootPlugin, + bool isBeforeChange, + string varName) + { + for (var s = 1; s < path.Length; s++) + { + var seg = path[s]; + var prevObsVar = $"{varName}_s{s - 1}"; + var curObsVar = $"{varName}_s{s}"; + var lambdaParam = $"{varName}_p{s}"; + var segType = seg.PropertyTypeFullName; - var lastSeg = $"__{variableName}_s{propertyPath.Length - 1}"; - sb.AppendLine( - $" var {variableName} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.DistinctUntilChanged({lastSeg});"); + if (rootPlugin is not null) + { + rootPlugin.EmitDeepChainInnerSegment(sb, prevObsVar, curObsVar, lambdaParam, seg, isBeforeChange); + } + else if (IsINPChanging(classInfo) && isBeforeChange) + { + _ = sb.AppendLine() + .AppendLine($""" + var {curObsVar} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Switch( + global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({prevObsVar}, + {lambdaParam} => {lambdaParam} != null + ? (global::System.IObservable<{segType}>)new global::ReactiveUI.Binding.Observables.PropertyChangingObservable<{segType}>( + (global::System.ComponentModel.INotifyPropertyChanging){lambdaParam}, + "{seg.PropertyName}", + (global::System.ComponentModel.INotifyPropertyChanging __o) => (({seg.DeclaringTypeFullName})__o).{seg.PropertyName}) + : (global::System.IObservable<{segType}>)new global::ReactiveUI.Binding.Observables.ReturnObservable<{segType}>(default({segType})))); + """); + } + else + { + _ = sb.AppendLine() + .AppendLine($""" + var {curObsVar} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Switch( + global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({prevObsVar}, + {lambdaParam} => (global::System.IObservable<{segType}>)new global::ReactiveUI.Binding.Observables.ReturnObservable<{segType}>( + {lambdaParam} != null ? (({seg.DeclaringTypeFullName}){lambdaParam}).{seg.PropertyName} : default({segType})))); + """); + } } } + /// + /// Emits the Select/Switch chain for a multi-segment property path, one stage per segment, and + /// the distinct-until-changed gate that terminates it. + /// + /// The string builder to append to. + /// The variable holding the chain root. + /// The property path being observed. + /// The root type's binding info, when known. + /// The observation plugin for the root type, when one matched. + /// The name of the variable the chain result is assigned to. + private static void EmitInlineDeepChain( + StringBuilder sb, + string rootVar, + EquatableArray propertyPath, + ClassBindingInfo? classInfo, + IObservationPlugin? plugin, + string variableName) + { + var seg0 = propertyPath[0]; + + if (plugin is not null) + { + plugin.EmitDeepChainRootSegment(sb, rootVar, seg0, GetTypeCastName(classInfo), false, $"__{variableName}_s0"); + } + else + { + _ = sb + .Append($" var __{variableName}_s0 = (global::System.IObservable<{seg0.PropertyTypeFullName}>") + .AppendLine($")new global::ReactiveUI.Binding.Observables.ReturnObservable<{seg0.PropertyTypeFullName}>({rootVar}.{seg0.PropertyName});"); + } + + for (var s = 1; s < propertyPath.Length; s++) + { + var seg = propertyPath[s]; + var prevVar = $"__{variableName}_s{s - 1}"; + var curVar = $"__{variableName}_s{s}"; + var lambdaParam = $"__p{s}"; + + if (plugin is not null) + { + plugin.EmitDeepChainInnerSegment(sb, prevVar, curVar, lambdaParam, seg, false); + continue; + } + + var segType = seg.PropertyTypeFullName; + var declType = seg.DeclaringTypeFullName; + _ = sb.AppendLine() + .AppendLine($""" + var {curVar} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Switch( + global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({prevVar}, + {lambdaParam} => (global::System.IObservable<{segType}>)new global::ReactiveUI.Binding.Observables.ReturnObservable<{segType}>( + {lambdaParam} != null ? (({declType}){lambdaParam}).{seg.PropertyName} : default({segType})))); + """); + } + + var lastSeg = $"__{variableName}_s{propertyPath.Length - 1}"; + _ = sb.AppendLine( + $" var {variableName} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.DistinctUntilChanged({lastSeg});"); + } + /// /// Computes the worker-method suffix for an observation invocation, keyed only by the source type and /// property expression(s) — not the call site. Call sites that share the same type and expression(s) @@ -898,7 +923,7 @@ private static void GenerateGroup( // Generate the concrete typed extension method overload GenerateConcreteOverload(sb, group, supportsCallerArgExpr, methodPrefix, groupAffinity); - sb.AppendLine(); + _ = sb.AppendLine(); // Generate the observation methods for each invocation in this group. Call sites that share the // same source type and property expression(s) produce an identical worker, so the method is keyed @@ -921,7 +946,7 @@ private static void GenerateGroup( var plugin = ObservationPluginRegistry.GetBestPlugin(classInfo); if (plugin?.RequiresHelperClasses == true) { - usedPluginKinds.Add(plugin.ObservationKind); + _ = usedPluginKinds.Add(plugin.ObservationKind); } } @@ -929,9 +954,7 @@ private static void GenerateGroup( } } - /// - /// Emits helper classes for all used plugins that require them, sorted for deterministic output order. - /// + /// Emits helper classes for all used plugins that require them, sorted for deterministic output order. /// The string builder to append to. /// The observation kinds of plugins requiring helper classes. private static void EmitUsedHelperClasses(StringBuilder sb, HashSet usedPluginKinds) @@ -945,35 +968,33 @@ private static void EmitUsedHelperClasses(StringBuilder sb, HashSet used } } - /// - /// Emits the trailing named-tuple projection lambda for a selector-less CombineLatest call. - /// + /// Emits the trailing named-tuple projection lambda for a selector-less CombineLatest call. /// The string builder to append to. /// The number of property path observables being combined. private static void EmitCombineLatestTupleProjection(StringBuilder sb, int propertyCount) { - sb.AppendLine(",") + _ = sb.AppendLine(",") .Append(" ("); for (var i = 0; i < propertyCount; i++) { - sb.Append('p').Append(i + 1); + _ = sb.Append('p').Append(i + 1); if (i < propertyCount - 1) { - sb.Append(", "); + _ = sb.Append(", "); } } - sb.Append(") => ("); + _ = sb.Append(") => ("); for (var i = 0; i < propertyCount; i++) { - sb.Append("property").Append(i + 1).Append(": p").Append(i + 1); + _ = sb.Append("property").Append(i + 1).Append(": p").Append(i + 1); if (i < propertyCount - 1) { - sb.Append(", "); + _ = sb.Append(", "); } } - sb.Append("));"); + _ = sb.Append("));"); } /// @@ -994,7 +1015,7 @@ private static void EmitOverloadSignature( int propCount, bool hasSelector) { - sb.AppendLine($""" + _ = sb.AppendLine($""" /// /// Concrete typed overload for {methodPrefix} on {first.SourceTypeFullName}. /// @@ -1005,34 +1026,32 @@ private static void EmitOverloadSignature( for (var i = 0; i < propCount; i++) { var type = first.PropertyPaths[i][first.PropertyPaths[i].Length - 1].PropertyTypeFullName; - sb.AppendLine( + _ = sb.AppendLine( $" global::System.Linq.Expressions.Expression> property{i + 1},"); } if (hasSelector) { - sb.AppendLine($" {GetSelectorType(first)} selector,"); + _ = sb.AppendLine($" {GetSelectorType(first)} selector,"); } if (supportsCallerArgExpr) { for (var i = 0; i < propCount; i++) { - sb.AppendLine( + _ = sb.AppendLine( $" [global::System.Runtime.CompilerServices.CallerArgumentExpression(\"property{i + 1}\")] string property{i + 1}Expression = \"\","); } } - sb.AppendLine(""" + _ = sb.AppendLine(""" [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { """); } - /// - /// Emits normalization that strips the static prefix from CallerArgumentExpression values. - /// + /// Emits normalization that strips the static prefix from CallerArgumentExpression values. /// The string builder to append to. /// Whether the target language version supports CallerArgumentExpression. /// The number of property expressions. @@ -1046,16 +1065,14 @@ private static void EmitStaticPrefixNormalization(StringBuilder sb, bool support for (var i = 0; i < propCount; i++) { var paramName = $"property{i + 1}Expression"; - sb.AppendLine( + _ = sb.AppendLine( $""" {paramName} = {paramName}.StartsWith("static ") ? {paramName}.Substring(7) : {paramName};"""); } - sb.AppendLine(); + _ = sb.AppendLine(); } - /// - /// Emits the if/else-if dispatch table that routes each matched invocation to its generated method. - /// + /// Emits the if/else-if dispatch table that routes each matched invocation to its generated method. /// The string builder to append to. /// The type group containing invocations that share a signature. /// Whether the target language version supports CallerArgumentExpression. @@ -1093,22 +1110,20 @@ private static void EmitDispatchTable( else { var suffix = CodeGeneratorHelpers.ComputePathSuffix(inv.CallerFilePath); - sb.AppendLine( - $""" {keyword} (callerLineNumber == {inv.CallerLineNumber} && callerFilePath.EndsWith("{CodeGeneratorHelpers.EscapeString(suffix)}",""" + - " global::System.StringComparison.OrdinalIgnoreCase))"); + _ = sb + .Append($""" {keyword} (callerLineNumber == {inv.CallerLineNumber} && callerFilePath.EndsWith("{CodeGeneratorHelpers.EscapeString(suffix)}",""") + .AppendLine(" global::System.StringComparison.OrdinalIgnoreCase))"); } branchIndex++; - sb.AppendLine(" {"); + _ = sb.AppendLine(" {"); var selectorArg = hasSelector ? ", selector" : string.Empty; - sb.AppendLine($" return __{methodPrefix}_{MethodSuffix(inv)}(objectToMonitor{selectorArg});") + _ = sb.AppendLine($" return __{methodPrefix}_{MethodSuffix(inv)}(objectToMonitor{selectorArg});") .AppendLine(" }"); } } - /// - /// Emits the CallerArgumentExpression match condition for a single invocation in the dispatch table. - /// + /// Emits the CallerArgumentExpression match condition for a single invocation in the dispatch table. /// The string builder to append to. /// The invocation info. /// The conditional keyword ("if" or "else if"). @@ -1119,37 +1134,31 @@ private static void EmitCallerArgExprCondition( string condition, int propCount) { - sb.Append($" {condition} ("); + _ = sb.Append($" {condition} ("); for (var p = 0; p < propCount; p++) { - sb.Append( + _ = sb.Append( $"property{p + 1}Expression == \"{CodeGeneratorHelpers.EscapeString(inv.ExpressionTexts[p])}\""); if (p < propCount - 1) { - sb.Append(" && "); + _ = sb.Append(" && "); } } - sb.AppendLine(")"); + _ = sb.AppendLine(")"); } - /// - /// Groups invocations by source and return type signature for overload generation. - /// + /// Groups invocations by source and return type signature for overload generation. /// The first invocation in the group, used for type information. /// All invocations sharing the same type signature. internal sealed record TypeGroup( InvocationInfo First, InvocationInfo[] Invocations) { - /// - /// Gets the fully qualified name of the source type. - /// - public string SourceTypeFullName => First.SourceTypeFullName; - - /// - /// Gets the fully qualified name of the return type. - /// - public string ReturnTypeFullName => First.ReturnTypeFullName; + /// Gets the fully qualified name of the source type. + internal string SourceTypeFullName => First.SourceTypeFullName; + + /// Gets the fully qualified name of the return type. + internal string ReturnTypeFullName => First.ReturnTypeFullName; } } diff --git a/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/OneWayBindCodeGenerator.cs b/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/OneWayBindCodeGenerator.cs index 2dabb15..5863e88 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/OneWayBindCodeGenerator.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/OneWayBindCodeGenerator.cs @@ -14,9 +14,10 @@ namespace ReactiveUI.Binding.SourceGenerators.CodeGeneration; /// internal static class OneWayBindCodeGenerator { - /// - /// Generates concrete typed overloads and binding methods for OneWayBind invocations. - /// + /// Name of the emitted local holding the source property observation, before conversion or scheduling. + private const string SourceObservableVariable = "sourceObs"; + + /// Generates concrete typed overloads and binding methods for OneWayBind invocations. /// All detected OneWayBind invocations. /// All detected class binding info. /// The consumer compilation's C# language-feature snapshot (dispatch strategy and nullable support). @@ -34,7 +35,7 @@ internal static class OneWayBindCodeGenerator var sb = new StringBuilder(); var supportsCallerArgExpr = features.SupportsCallerArgExpr; CodeGeneratorHelpers.AppendExtensionClassHeader(sb, features); - sb.AppendLine(); + _ = sb.AppendLine(); var groups = GroupByTypeSignature(invocations); @@ -43,7 +44,7 @@ internal static class OneWayBindCodeGenerator var group = groups[g]; GenerateConcreteOverload(sb, group, supportsCallerArgExpr, features.SupportsNullable); - sb.AppendLine(); + _ = sb.AppendLine(); for (var i = 0; i < group.Invocations.Length; i++) { @@ -53,20 +54,18 @@ internal static class OneWayBindCodeGenerator inv.SourceTypeFullName, inv.CallerFilePath, inv.CallerLineNumber, - inv.SourceExpressionText + "|" + inv.TargetExpressionText); + $"{inv.SourceExpressionText}|{inv.TargetExpressionText}"); GenerateOneWayBindMethod(sb, inv, sourceClassInfo, suffix); } } CodeGeneratorHelpers.AppendExtensionClassFooter(sb); - sb.AppendLine(); + _ = sb.AppendLine(); return sb.ToString(); } - /// - /// Groups OneWayBind invocations by their type signature for overload generation. - /// + /// Groups OneWayBind invocations by their type signature for overload generation. /// The OneWayBind invocations to group. /// A list of grouped invocations sharing the same type signature. internal static List GroupByTypeSignature(ImmutableArray invocations) @@ -76,9 +75,7 @@ internal static List GroupByTypeSignature(ImmutableArray GroupByTypeSignature(ImmutableArray - /// Generates the concrete typed overload using the appropriate dispatch strategy. - /// + /// Generates the concrete typed overload using the appropriate dispatch strategy. /// The string builder to append to. /// The binding type group. /// Whether CallerArgumentExpression is available. @@ -129,9 +124,7 @@ internal static void GenerateConcreteOverload( } } - /// - /// Generates the CallerArgumentExpression-based overload for OneWayBind dispatch. - /// + /// Generates the CallerArgumentExpression-based overload for OneWayBind dispatch. /// The string builder to append to. /// The binding type group. /// Whether the target supports nullable reference types (C# 8+). @@ -144,7 +137,7 @@ internal static void GenerateCallerArgExprOverload( var targetPropType = CodeGeneratorHelpers.NullableSelectorLeafType(group.Invocations[0].TargetPropertyPath, supportsNullable); var returnType = FormatReturnType(group); - sb.AppendLine($""" + _ = sb.AppendLine($""" /// /// Concrete typed overload for OneWayBind from {group.SourceTypeFullName} to {group.TargetTypeFullName}. /// Uses CallerArgumentExpression for dispatch. @@ -152,14 +145,14 @@ internal static void GenerateCallerArgExprOverload( public static {returnType} OneWayBind( this {group.TargetTypeFullName} view, {group.SourceTypeFullName} viewModel, - global::System.Linq.Expressions.Expression> vmProperty, + global::System.Linq.Expressions.Expression> viewModelProperty, global::System.Linq.Expressions.Expression> viewProperty, """); AppendExtraParameters(sb, group); - sb.AppendLine(""" - [global::System.Runtime.CompilerServices.CallerArgumentExpression("vmProperty")] string vmPropertyExpression = "", + _ = sb.AppendLine(""" + [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewModelProperty")] string viewModelPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewProperty")] string viewPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) @@ -176,10 +169,10 @@ internal static void GenerateCallerArgExprOverload( inv.SourceTypeFullName, inv.CallerFilePath, inv.CallerLineNumber, - inv.SourceExpressionText + "|" + inv.TargetExpressionText); + $"{inv.SourceExpressionText}|{inv.TargetExpressionText}"); - sb.AppendLine($$""" - {{condition}} (vmPropertyExpression == "{{escapedSourceExpr}}" + _ = sb.AppendLine($$""" + {{condition}} (viewModelPropertyExpression == "{{escapedSourceExpr}}" && viewPropertyExpression == "{{escapedTargetExpr}}") { return __OneWayBind_{{methodSuffix}}(viewModel, view{{FormatExtraArgs(group)}}); @@ -187,16 +180,14 @@ internal static void GenerateCallerArgExprOverload( """); } - sb.AppendLine(""" + _ = sb.AppendLine(""" throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } """); } - /// - /// Generates the CallerFilePath-based overload for OneWayBind dispatch. - /// + /// Generates the CallerFilePath-based overload for OneWayBind dispatch. /// The string builder to append to. /// The binding type group. /// Whether the target supports nullable reference types (C# 8+). @@ -209,7 +200,7 @@ internal static void GenerateCallerFilePathOverload( var targetPropType = CodeGeneratorHelpers.NullableSelectorLeafType(group.Invocations[0].TargetPropertyPath, supportsNullable); var returnType = FormatReturnType(group); - sb.AppendLine($""" + _ = sb.AppendLine($""" /// /// Concrete typed overload for OneWayBind from {group.SourceTypeFullName} to {group.TargetTypeFullName}. /// Uses CallerFilePath + CallerLineNumber for dispatch. @@ -217,13 +208,13 @@ internal static void GenerateCallerFilePathOverload( public static {returnType} OneWayBind( this {group.TargetTypeFullName} view, {group.SourceTypeFullName} viewModel, - global::System.Linq.Expressions.Expression> vmProperty, + global::System.Linq.Expressions.Expression> viewModelProperty, global::System.Linq.Expressions.Expression> viewProperty, """); AppendExtraParameters(sb, group); - sb.AppendLine(""" + _ = sb.AppendLine(""" [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { @@ -238,9 +229,9 @@ internal static void GenerateCallerFilePathOverload( inv.SourceTypeFullName, inv.CallerFilePath, inv.CallerLineNumber, - inv.SourceExpressionText + "|" + inv.TargetExpressionText); + $"{inv.SourceExpressionText}|{inv.TargetExpressionText}"); - sb.AppendLine($$""" + _ = sb.AppendLine($$""" {{condition}} (callerLineNumber == {{inv.CallerLineNumber}} && callerFilePath.EndsWith("{{CodeGeneratorHelpers.EscapeString(pathSuffix)}}", global::System.StringComparison.OrdinalIgnoreCase)) { @@ -249,16 +240,14 @@ internal static void GenerateCallerFilePathOverload( """); } - sb.AppendLine(""" + _ = sb.AppendLine(""" throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } """); } - /// - /// Generates a private OneWayBind method for a specific invocation. - /// + /// Generates a private OneWayBind method for a specific invocation. /// The string builder to append to. /// The binding invocation info. /// The source type class binding info. @@ -270,7 +259,7 @@ internal static void GenerateOneWayBindMethod( string suffix) { var viewPropertyAccess = CodeGeneratorHelpers.BuildPropertySetterChain("view", inv.TargetPropertyPath); - var vmPathComment = CodeGeneratorHelpers.BuildPropertyPathString(inv.SourcePropertyPath); + var viewModelPathComment = CodeGeneratorHelpers.BuildPropertyPathString(inv.SourcePropertyPath); var viewPathComment = CodeGeneratorHelpers.BuildPropertyPathString(inv.TargetPropertyPath); var extraParams = FormatExtraMethodParams(inv); @@ -278,10 +267,10 @@ internal static void GenerateOneWayBindMethod( var schedulerComment = inv.HasScheduler ? " (with scheduler)" : string.Empty; var returnType = FormatMethodReturnType(inv); - sb.AppendLine($$""" + _ = sb.AppendLine($$""" private static {{returnType}} __OneWayBind_{{suffix}}({{inv.SourceTypeFullName}} viewModel, {{inv.TargetTypeFullName}} view{{extraParams}}) { - // OneWayBind: {{vmPathComment}} -> {{viewPathComment}}{{conversionComment}}{{schedulerComment}} + // OneWayBind: {{viewModelPathComment}} -> {{viewPathComment}}{{conversionComment}}{{schedulerComment}} """); // Emit inline observation code instead of delegating to WhenChanged dispatch @@ -291,28 +280,13 @@ internal static void GenerateOneWayBindMethod( inv.SourcePropertyPath, inv.SourcePropertyTypeFullName, sourceClassInfo, - "sourceObs"); - - if (inv.HasConversion || inv.HasScheduler) - { - var currentVar = "sourceObs"; + SourceObservableVariable); - if (inv.HasConversion) - { - var nextVar = inv.HasScheduler ? "__selected" : "bindObs"; - sb.AppendLine( - $" var {nextVar} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({currentVar}, selector);"); - currentVar = nextVar; - } - - if (inv.HasScheduler) - { - sb.AppendLine( - $" var bindObs = new global::ReactiveUI.Binding.Reactive.ObserveOnObservable<{inv.TargetPropertyTypeFullName}>({currentVar}, scheduler);"); - currentVar = "bindObs"; - } + var currentVar = inv.HasConversion || inv.HasScheduler + ? EmitConversionAndSchedulerStages(sb, inv) + : SourceObservableVariable; - sb.AppendLine($$""" + _ = sb.AppendLine($$""" var sub = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Subscribe({{currentVar}}, value => { @@ -326,38 +300,17 @@ internal static void GenerateOneWayBindMethod( sub); } """) - .AppendLine(); - } - else - { - sb.AppendLine($$""" - - var sub = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Subscribe(sourceObs, value => - { - {{viewPropertyAccess}} = value; - }); - - return new global::ReactiveUI.Binding.ReactiveBinding<{{inv.TargetTypeFullName}}, {{inv.TargetPropertyTypeFullName}}>( - view, - sourceObs, - global::ReactiveUI.Binding.BindingDirection.OneWay, - sub); - } - """) - .AppendLine(); - } + .AppendLine(); } - /// - /// Appends extra parameters (selector, scheduler) to the concrete overload signature. - /// + /// Appends extra parameters (selector, scheduler) to the concrete overload signature. /// The string builder to append to. /// The binding type group. internal static void AppendExtraParameters(StringBuilder sb, BindingTypeGroup group) { if (group.HasConversion) { - sb.AppendLine( + _ = sb.AppendLine( $" global::System.Func<{group.SourcePropertyTypeFullName}, {group.TargetPropertyTypeFullName}> selector,"); } @@ -366,12 +319,10 @@ internal static void AppendExtraParameters(StringBuilder sb, BindingTypeGroup gr return; } - sb.AppendLine(" global::System.Reactive.Concurrency.IScheduler scheduler,"); + _ = sb.AppendLine(" global::System.Reactive.Concurrency.IScheduler scheduler,"); } - /// - /// Formats extra arguments (selector, scheduler) for forwarding to the binding method. - /// + /// Formats extra arguments (selector, scheduler) for forwarding to the binding method. /// The binding type group. /// Extra arguments string or empty. internal static string FormatExtraArgs(BindingTypeGroup group) @@ -379,20 +330,18 @@ internal static string FormatExtraArgs(BindingTypeGroup group) var sb = new StringBuilder(); if (group.HasConversion) { - sb.Append(", selector"); + _ = sb.Append(", selector"); } if (group.HasScheduler) { - sb.Append(", scheduler"); + _ = sb.Append(", scheduler"); } return sb.ToString(); } - /// - /// Formats extra method parameters for the private binding method signature. - /// + /// Formats extra method parameters for the private binding method signature. /// The binding invocation info. /// Extra parameters string for selector and scheduler parameters. internal static string FormatExtraMethodParams(BindingInvocationInfo inv) @@ -400,21 +349,19 @@ internal static string FormatExtraMethodParams(BindingInvocationInfo inv) var sb = new StringBuilder(); if (inv.HasConversion) { - sb.Append( + _ = sb.Append( $", global::System.Func<{inv.SourcePropertyTypeFullName}, {inv.TargetPropertyTypeFullName}> selector"); } if (inv.HasScheduler) { - sb.Append(", global::System.Reactive.Concurrency.IScheduler scheduler"); + _ = sb.Append(", global::System.Reactive.Concurrency.IScheduler scheduler"); } return sb.ToString(); } - /// - /// Formats the return type for a concrete OneWayBind overload. - /// + /// Formats the return type for a concrete OneWayBind overload. /// The binding type group. /// The fully qualified return type string. internal static string FormatReturnType(BindingTypeGroup group) @@ -423,14 +370,38 @@ internal static string FormatReturnType(BindingTypeGroup group) return $"global::ReactiveUI.Binding.IReactiveBinding<{group.TargetTypeFullName}, {valueType}>"; } - /// - /// Formats the return type for a private OneWayBind method. - /// + /// Formats the return type for a private OneWayBind method. /// The binding invocation info. /// The fully qualified return type string. internal static string FormatMethodReturnType(BindingInvocationInfo inv) => $"global::ReactiveUI.Binding.IReactiveBinding<{inv.TargetTypeFullName}, {inv.TargetPropertyTypeFullName}>"; + /// Emits the conversion and scheduler stages between the source observation and the subscription. + /// The string builder to append to. + /// The binding invocation info. + /// The variable name the subscription should read from. + private static string EmitConversionAndSchedulerStages(StringBuilder sb, BindingInvocationInfo inv) + { + var currentVar = SourceObservableVariable; + + if (inv.HasConversion) + { + var nextVar = inv.HasScheduler ? "__selected" : "bindObs"; + _ = sb.AppendLine( + $" var {nextVar} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({currentVar}, selector);"); + currentVar = nextVar; + } + + if (inv.HasScheduler) + { + _ = sb.AppendLine( + $" var bindObs = new global::ReactiveUI.Binding.Reactive.ObserveOnObservable<{inv.TargetPropertyTypeFullName}>({currentVar}, scheduler);"); + currentVar = "bindObs"; + } + + return currentVar; + } + /// /// Represents a grouping of binding invocations categorized by source type, target type, /// source property type, target property type, presence of conversion, and presence of a scheduler. diff --git a/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/WhenAnyCodeGenerator.cs b/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/WhenAnyCodeGenerator.cs index 4144fa2..5877444 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/WhenAnyCodeGenerator.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/WhenAnyCodeGenerator.cs @@ -15,9 +15,7 @@ namespace ReactiveUI.Binding.SourceGenerators.CodeGeneration; /// internal static class WhenAnyCodeGenerator { - /// - /// Generates concrete typed overloads and observation methods for WhenAny invocations. - /// + /// Generates concrete typed overloads and observation methods for WhenAny invocations. /// All detected WhenAny invocations. /// All detected class binding info for type mechanism lookup. /// The consumer compilation's C# language-feature snapshot (dispatch strategy and nullable support). @@ -35,7 +33,7 @@ internal static class WhenAnyCodeGenerator var sb = new StringBuilder(); var supportsCallerArgExpr = features.SupportsCallerArgExpr; CodeGeneratorHelpers.AppendExtensionClassHeader(sb, features); - sb.AppendLine(); + _ = sb.AppendLine(); // Group invocations by their method signature var groups = ObservationCodeGenerator.GroupByTypeSignature(invocations); @@ -46,7 +44,7 @@ internal static class WhenAnyCodeGenerator // Generate the concrete typed extension method overload GenerateConcreteOverload(sb, group, supportsCallerArgExpr, features.SupportsNullable); - sb.AppendLine(); + _ = sb.AppendLine(); // Generate the observation methods for each invocation in this group for (var i = 0; i < group.Invocations.Length; i++) @@ -63,7 +61,7 @@ internal static class WhenAnyCodeGenerator } CodeGeneratorHelpers.AppendExtensionClassFooter(sb); - sb.AppendLine(); + _ = sb.AppendLine(); return sb.ToString(); } @@ -85,7 +83,7 @@ internal static void GenerateConcreteOverload( var first = group.First; var propCount = first.PropertyPaths.Length; - sb.AppendLine($""" + _ = sb.AppendLine($""" /// /// Concrete typed overload for WhenAny on {first.SourceTypeFullName}. /// @@ -96,23 +94,23 @@ internal static void GenerateConcreteOverload( for (var i = 0; i < propCount; i++) { var type = CodeGeneratorHelpers.NullableSelectorLeafType(first.PropertyPaths[i], supportsNullable); - sb.AppendLine( + _ = sb.AppendLine( $" global::System.Linq.Expressions.Expression> property{i + 1},"); } // WhenAny always has a selector that takes IObservedChange parameters - sb.Append(" ").Append(GetWhenAnySelectorType(first)).AppendLine(" selector,"); + _ = sb.Append(" ").Append(GetWhenAnySelectorType(first)).AppendLine(" selector,"); if (supportsCallerArgExpr) { for (var i = 0; i < propCount; i++) { - sb.AppendLine( + _ = sb.AppendLine( $" [global::System.Runtime.CompilerServices.CallerArgumentExpression(\"property{i + 1}\")] string property{i + 1}Expression = \"\","); } } - sb.AppendLine(""" + _ = sb.AppendLine(""" [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { @@ -124,7 +122,7 @@ internal static void GenerateConcreteOverload( // Runtime fallback GenerateRuntimeFallback(sb, first); - sb.AppendLine(" }"); + _ = sb.AppendLine(" }"); } /// @@ -153,7 +151,7 @@ internal static void GenerateObservationMethod( { var selectorType = GetWhenAnySelectorType(inv); - sb.AppendLine($$""" + _ = sb.AppendLine($$""" private static global::System.IObservable<{{inv.ReturnTypeFullName}}> __WhenAny_{{suffix}}({{inv.SourceTypeFullName}} obj, {{selectorType}} selector) { """); @@ -167,14 +165,12 @@ internal static void GenerateObservationMethod( GenerateMultiPropertyWhenAny(sb, inv, classInfo); } - sb.AppendLine() + _ = sb.AppendLine() .AppendLine(" }") .AppendLine(); } - /// - /// Generates single-property WhenAny observation: observe property, wrap in ObservedChange, apply selector. - /// + /// Generates single-property WhenAny observation: observe property, wrap in ObservedChange, apply selector. /// The string builder to append to. /// The invocation info. /// The class binding info for the source type, or null. @@ -196,11 +192,11 @@ internal static void GenerateSinglePropertyWhenAny( ObservationCodeGenerator.GenerateShallowObservableVariable(sb, path, classInfo, false, "__propObs0"); } - sb.AppendLine() + _ = sb.AppendLine() .AppendLine(); // Wrap in ObservedChange and apply selector - sb.Append($""" + _ = sb.Append($""" return global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select(__propObs0, value => selector(new global::ReactiveUI.Binding.ObservedChange<{inv.SourceTypeFullName}, {leafType}>(obj, null, value))); """); @@ -222,7 +218,7 @@ internal static void GenerateMultiPropertyWhenAny( for (var i = 0; i < inv.PropertyPaths.Length; i++) { var path = inv.PropertyPaths[i]; - var varName = "__propObs" + i; + var varName = $"__propObs{i}"; if (path.Length > 1) { @@ -233,47 +229,47 @@ internal static void GenerateMultiPropertyWhenAny( ObservationCodeGenerator.GenerateShallowObservableVariable(sb, path, classInfo, false, varName); } - sb.AppendLine() + _ = sb.AppendLine() .AppendLine(); } - sb.AppendLine(" return global::ReactiveUI.Binding.Observables.CombineLatestObservable.Create("); + _ = sb.AppendLine(" return global::ReactiveUI.Binding.Observables.CombineLatestObservable.Create("); for (var i = 0; i < inv.PropertyPaths.Length; i++) { - sb.Append(" __propObs").Append(i); + _ = sb.Append(" __propObs").Append(i); if (i < inv.PropertyPaths.Length - 1) { - sb.AppendLine(","); + _ = sb.AppendLine(","); } } - sb.AppendLine(","); + _ = sb.AppendLine(","); // Selector lambda: wrap each value in ObservedChange - sb.Append(" ("); + _ = sb.Append(" ("); for (var i = 0; i < inv.PropertyPaths.Length; i++) { - sb.Append('v').Append(i + 1); + _ = sb.Append('v').Append(i + 1); if (i < inv.PropertyPaths.Length - 1) { - sb.Append(", "); + _ = sb.Append(", "); } } - sb.Append(") => selector("); + _ = sb.Append(") => selector("); for (var i = 0; i < inv.PropertyPaths.Length; i++) { var path = inv.PropertyPaths[i]; var leafType = path[path.Length - 1].PropertyTypeFullName; - sb.Append( + _ = sb.Append( $"new global::ReactiveUI.Binding.ObservedChange<{inv.SourceTypeFullName}, {leafType}>(obj, null, v{i + 1})"); if (i < inv.PropertyPaths.Length - 1) { - sb.Append(", "); + _ = sb.Append(", "); } } - sb.Append("));"); + _ = sb.Append("));"); } /// @@ -289,16 +285,14 @@ internal static string GetWhenAnySelectorType(InvocationInfo inv) { var path = inv.PropertyPaths[i]; var leafType = path[path.Length - 1].PropertyTypeFullName; - sb.Append($"global::ReactiveUI.Binding.IObservedChange<{inv.SourceTypeFullName}, {leafType}>, "); + _ = sb.Append($"global::ReactiveUI.Binding.IObservedChange<{inv.SourceTypeFullName}, {leafType}>, "); } - sb.Append(inv.ReturnTypeFullName).Append('>'); + _ = sb.Append(inv.ReturnTypeFullName).Append('>'); return sb.ToString(); } - /// - /// Emits normalization that strips the static prefix from CallerArgumentExpression values. - /// + /// Emits normalization that strips the static prefix from CallerArgumentExpression values. /// The string builder to append to. /// Whether the target language version supports CallerArgumentExpression. /// The number of property expressions. @@ -312,16 +306,14 @@ private static void EmitStaticPrefixNormalization(StringBuilder sb, bool support for (var i = 0; i < propCount; i++) { var paramName = $"property{i + 1}Expression"; - sb.AppendLine( + _ = sb.AppendLine( $""" {paramName} = {paramName}.StartsWith("static ") ? {paramName}.Substring(7) : {paramName};"""); } - sb.AppendLine(); + _ = sb.AppendLine(); } - /// - /// Emits the if/else-if dispatch table that routes each matched WhenAny invocation to its generated method. - /// + /// Emits the if/else-if dispatch table that routes each matched WhenAny invocation to its generated method. /// The string builder to append to. /// The type group containing invocations that share a signature. /// Whether the target language version supports CallerArgumentExpression. @@ -344,9 +336,9 @@ private static void EmitDispatchTable( else { var suffix = CodeGeneratorHelpers.ComputePathSuffix(inv.CallerFilePath); - sb.AppendLine( - $""" {condition} (callerLineNumber == {inv.CallerLineNumber} && callerFilePath.EndsWith("{CodeGeneratorHelpers.EscapeString(suffix)}",""" + - " global::System.StringComparison.OrdinalIgnoreCase))"); + _ = sb + .Append($""" {condition} (callerLineNumber == {inv.CallerLineNumber} && callerFilePath.EndsWith("{CodeGeneratorHelpers.EscapeString(suffix)}",""") + .AppendLine(" global::System.StringComparison.OrdinalIgnoreCase))"); } var methodSuffix = CodeGeneratorHelpers.ComputeStableMethodSuffix( @@ -354,15 +346,13 @@ private static void EmitDispatchTable( inv.CallerFilePath, inv.CallerLineNumber, string.Join("|", inv.ExpressionTexts)); - sb.AppendLine(" {") + _ = sb.AppendLine(" {") .AppendLine($" return __WhenAny_{methodSuffix}(objectToMonitor, selector);") .AppendLine(" }"); } } - /// - /// Emits the CallerArgumentExpression match condition for a single invocation in the dispatch table. - /// + /// Emits the CallerArgumentExpression match condition for a single invocation in the dispatch table. /// The string builder to append to. /// The invocation info. /// The conditional keyword ("if" or "else if"). @@ -373,17 +363,17 @@ private static void EmitCallerArgExprCondition( string condition, int propCount) { - sb.Append($" {condition} ("); + _ = sb.Append($" {condition} ("); for (var p = 0; p < propCount; p++) { - sb.Append( + _ = sb.Append( $"property{p + 1}Expression == \"{CodeGeneratorHelpers.EscapeString(inv.ExpressionTexts[p])}\""); if (p < propCount - 1) { - sb.Append(" && "); + _ = sb.Append(" && "); } } - sb.AppendLine(")"); + _ = sb.AppendLine(")"); } } diff --git a/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/WhenAnyObservableCodeGenerator.cs b/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/WhenAnyObservableCodeGenerator.cs index bbd8ec9..78434b1 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/WhenAnyObservableCodeGenerator.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/CodeGeneration/WhenAnyObservableCodeGenerator.cs @@ -15,14 +15,10 @@ namespace ReactiveUI.Binding.SourceGenerators.CodeGeneration; /// internal static class WhenAnyObservableCodeGenerator { - /// - /// The base name used to build emitted local variable identifiers for the raw observable property. - /// + /// The base name used to build emitted local variable identifiers for the raw observable property. private const string ObsPropertyVarName = "__obsProperty"; - /// - /// Generates concrete typed overloads and observation methods for WhenAnyObservable invocations. - /// + /// Generates concrete typed overloads and observation methods for WhenAnyObservable invocations. /// All detected WhenAnyObservable invocations. /// All detected class binding info for type mechanism lookup. /// The consumer compilation's C# language-feature snapshot (dispatch strategy and nullable support). @@ -37,10 +33,10 @@ internal static class WhenAnyObservableCodeGenerator return null; } - var sb = new StringBuilder(invocations.Length * 1_024); + var sb = new StringBuilder(invocations.Length * CodeGeneratorHelpers.PerInvocationBufferCapacity); var supportsCallerArgExpr = features.SupportsCallerArgExpr; CodeGeneratorHelpers.AppendExtensionClassHeader(sb, features); - sb.AppendLine(); + _ = sb.AppendLine(); // Group invocations by their method signature var groups = GroupByTypeSignature(invocations); @@ -51,7 +47,7 @@ internal static class WhenAnyObservableCodeGenerator // Generate the concrete typed extension method overload GenerateConcreteOverload(sb, group, supportsCallerArgExpr, features.SupportsNullable); - sb.AppendLine(); + _ = sb.AppendLine(); // Generate the observation methods for each invocation in this group for (var i = 0; i < group.Invocations.Length; i++) @@ -68,14 +64,12 @@ internal static class WhenAnyObservableCodeGenerator } CodeGeneratorHelpers.AppendExtensionClassFooter(sb); - sb.AppendLine(); + _ = sb.AppendLine(); return sb.ToString(); } - /// - /// Generates a concrete typed extension method overload with dispatch logic for WhenAnyObservable. - /// + /// Generates a concrete typed extension method overload with dispatch logic for WhenAnyObservable. /// The string builder to append to. /// The type group containing invocations that share a signature. /// Whether the target language version supports CallerArgumentExpression. @@ -90,7 +84,7 @@ internal static void GenerateConcreteOverload( var propCount = first.PropertyPaths.Length; var hasSelector = first.HasSelector; - sb.AppendLine($""" + _ = sb.AppendLine($""" /// /// Concrete typed overload for WhenAnyObservable on {first.SourceTypeFullName}. /// @@ -102,25 +96,25 @@ internal static void GenerateConcreteOverload( { var innerType = first.InnerObservableTypeFullNames[i]; var obsType = $"global::System.IObservable<{innerType}>{(supportsNullable ? "?" : string.Empty)}"; - sb.AppendLine( + _ = sb.AppendLine( $" global::System.Linq.Expressions.Expression> obs{i + 1},"); } if (hasSelector) { - sb.Append(" ").Append(GetSelectorType(first)).AppendLine(" selector,"); + _ = sb.Append(" ").Append(GetSelectorType(first)).AppendLine(" selector,"); } if (supportsCallerArgExpr) { for (var i = 0; i < propCount; i++) { - sb.AppendLine( + _ = sb.AppendLine( $" [global::System.Runtime.CompilerServices.CallerArgumentExpression(\"obs{i + 1}\")] string obs{i + 1}Expression = \"\","); } } - sb.AppendLine(""" + _ = sb.AppendLine(""" [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { @@ -130,14 +124,12 @@ internal static void GenerateConcreteOverload( EmitDispatchTable(sb, group, supportsCallerArgExpr, propCount, hasSelector); // Runtime fallback: throw for now (WhenAnyObservable doesn't have a simple fallback path) - sb.AppendLine( + _ = sb.AppendLine( " throw new global::System.InvalidOperationException(\"No generated WhenAnyObservable dispatch matched. This indicates a source generator caching issue.\");") .AppendLine(" }"); } - /// - /// Generates an observation method for a single WhenAnyObservable invocation. - /// + /// Generates an observation method for a single WhenAnyObservable invocation. /// The string builder to append to. /// The invocation info. /// The class binding info for the source type, or null. @@ -148,9 +140,9 @@ internal static void GenerateObservationMethod( ClassBindingInfo? classInfo, string suffix) { - var selectorParam = inv.HasSelector ? ", " + GetSelectorType(inv) + " selector" : string.Empty; + var selectorParam = inv.HasSelector ? $", {GetSelectorType(inv)} selector" : string.Empty; - sb.AppendLine($$""" + _ = sb.AppendLine($$""" private static global::System.IObservable<{{inv.ReturnTypeFullName}}> __WhenAnyObservable_{{suffix}}({{inv.SourceTypeFullName}} obj{{selectorParam}}) { """); @@ -168,14 +160,12 @@ internal static void GenerateObservationMethod( GenerateMultiObservableCombineLatest(sb, inv, classInfo); } - sb.AppendLine() + _ = sb.AppendLine() .AppendLine(" }") .AppendLine(); } - /// - /// Generates a single-property Switch pattern: observe the IObservable property, switch to its latest value. - /// + /// Generates a single-property Switch pattern: observe the IObservable property, switch to its latest value. /// The string builder to append to. /// The invocation info. /// The class binding info for the source type, or null. @@ -197,20 +187,18 @@ internal static void GenerateSingleObservableSwitch( ObservationCodeGenerator.GenerateShallowObservableVariable(sb, path, classInfo, false, ObsPropertyVarName); } - sb.AppendLine() + _ = sb.AppendLine() .AppendLine(); // Switch pattern: take the observable property value, replace null with Empty, and switch - sb.Append($""" + _ = sb.Append($""" return global::ReactiveUI.Binding.Observables.RxBindingExtensions.Switch( global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select(__obsProperty, __obs => __obs ?? (global::System.IObservable<{innerType}>)global::ReactiveUI.Binding.Observables.EmptyObservable<{innerType}>.Instance)); """); } - /// - /// Generates a multi-property Merge pattern: observe each IObservable property, switch each, then merge. - /// + /// Generates a multi-property Merge pattern: observe each IObservable property, switch each, then merge. /// The string builder to append to. /// The invocation info. /// The class binding info for the source type, or null. @@ -225,7 +213,7 @@ internal static void GenerateMultiObservableMerge( var path = inv.PropertyPaths[i]; var innerType = inv.InnerObservableTypeFullNames[i]; var rawVar = ObsPropertyVarName + i; - var switchedVar = "__switched" + i; + var switchedVar = $"__switched{i}"; if (path.Length > 1) { @@ -236,7 +224,7 @@ internal static void GenerateMultiObservableMerge( ObservationCodeGenerator.GenerateShallowObservableVariable(sb, path, classInfo, false, rawVar); } - sb.AppendLine() + _ = sb.AppendLine() .AppendLine() .AppendLine($""" var {switchedVar} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Switch( @@ -246,17 +234,17 @@ internal static void GenerateMultiObservableMerge( .AppendLine(); } - sb.AppendLine(" return global::ReactiveUI.Binding.Observables.RxBindingExtensions.Merge("); + _ = sb.AppendLine(" return global::ReactiveUI.Binding.Observables.RxBindingExtensions.Merge("); for (var i = 0; i < inv.PropertyPaths.Length; i++) { - sb.Append(" __switched").Append(i); + _ = sb.Append(" __switched").Append(i); if (i < inv.PropertyPaths.Length - 1) { - sb.AppendLine(","); + _ = sb.AppendLine(","); } } - sb.Append(");"); + _ = sb.Append(");"); } /// @@ -277,7 +265,7 @@ internal static void GenerateMultiObservableCombineLatest( var path = inv.PropertyPaths[i]; var innerType = inv.InnerObservableTypeFullNames[i]; var rawVar = ObsPropertyVarName + i; - var switchedVar = "__switched" + i; + var switchedVar = $"__switched{i}"; if (path.Length > 1) { @@ -288,7 +276,7 @@ internal static void GenerateMultiObservableCombineLatest( ObservationCodeGenerator.GenerateShallowObservableVariable(sb, path, classInfo, false, rawVar); } - sb.AppendLine() + _ = sb.AppendLine() .AppendLine() .AppendLine($""" var {switchedVar} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Switch( @@ -298,18 +286,16 @@ internal static void GenerateMultiObservableCombineLatest( .AppendLine(); } - sb.AppendLine(" return global::ReactiveUI.Binding.Observables.CombineLatestObservable.Create("); + _ = sb.AppendLine(" return global::ReactiveUI.Binding.Observables.CombineLatestObservable.Create("); for (var i = 0; i < inv.PropertyPaths.Length; i++) { - sb.Append(" __switched").Append(i).AppendLine(","); + _ = sb.Append(" __switched").Append(i).AppendLine(","); } - sb.Append(" selector);"); + _ = sb.Append(" selector);"); } - /// - /// Gets the Func type signature for a WhenAnyObservable selector parameter. - /// + /// Gets the Func type signature for a WhenAnyObservable selector parameter. /// The invocation info. /// A fully qualified Func type string. internal static string GetSelectorType(WhenAnyObservableInvocationInfo inv) @@ -317,27 +303,25 @@ internal static string GetSelectorType(WhenAnyObservableInvocationInfo inv) var sb = new StringBuilder("global::System.Func<"); for (var i = 0; i < inv.InnerObservableTypeFullNames.Length; i++) { - sb.Append(inv.InnerObservableTypeFullNames[i]).Append(", "); + _ = sb.Append(inv.InnerObservableTypeFullNames[i]).Append(", "); } - sb.Append(inv.ReturnTypeFullName).Append('>'); + _ = sb.Append(inv.ReturnTypeFullName).Append('>'); return sb.ToString(); } - /// - /// Groups WhenAnyObservable invocations by their type signature for overload generation. - /// + /// Groups WhenAnyObservable invocations by their type signature for overload generation. /// All detected invocations. /// A list of type groups. internal static List GroupByTypeSignature(ImmutableArray invocations) { var groupMap = new Dictionary>(invocations.Length); - var keySb = new StringBuilder(128); + var keySb = new StringBuilder(CodeGeneratorHelpers.FragmentBufferCapacity); for (var i = 0; i < invocations.Length; i++) { var inv = invocations[i]; - keySb.Clear() + _ = keySb.Clear() .Append(inv.SourceTypeFullName).Append('|') .Append(inv.ReturnTypeFullName).Append('|') .Append(inv.PropertyPaths.Length).Append('|') @@ -345,7 +329,7 @@ internal static List GroupByTypeSignature(ImmutableArray GroupByTypeSignature(ImmutableArray - /// Emits normalization that strips the static prefix from CallerArgumentExpression values. - /// + /// Emits normalization that strips the static prefix from CallerArgumentExpression values. /// The string builder to append to. /// Whether the target language version supports CallerArgumentExpression. /// The number of observable expressions. @@ -384,16 +366,14 @@ private static void EmitStaticPrefixNormalization(StringBuilder sb, bool support for (var i = 0; i < propCount; i++) { var paramName = $"obs{i + 1}Expression"; - sb.AppendLine( + _ = sb.AppendLine( $""" {paramName} = {paramName}.StartsWith("static ") ? {paramName}.Substring(7) : {paramName};"""); } - sb.AppendLine(); + _ = sb.AppendLine(); } - /// - /// Emits the if/else-if dispatch table that routes each matched invocation to its generated method. - /// + /// Emits the if/else-if dispatch table that routes each matched invocation to its generated method. /// The string builder to append to. /// The type group containing invocations that share a signature. /// Whether the target language version supports CallerArgumentExpression. @@ -418,26 +398,24 @@ private static void EmitDispatchTable( else { var suffix = CodeGeneratorHelpers.ComputePathSuffix(inv.CallerFilePath); - sb.AppendLine( - $""" {condition} (callerLineNumber == {inv.CallerLineNumber} && callerFilePath.EndsWith("{CodeGeneratorHelpers.EscapeString(suffix)}",""" + - " global::System.StringComparison.OrdinalIgnoreCase))"); + _ = sb + .Append($""" {condition} (callerLineNumber == {inv.CallerLineNumber} && callerFilePath.EndsWith("{CodeGeneratorHelpers.EscapeString(suffix)}",""") + .AppendLine(" global::System.StringComparison.OrdinalIgnoreCase))"); } - sb.AppendLine(" {"); + _ = sb.AppendLine(" {"); var selectorArg = hasSelector ? ", selector" : string.Empty; var methodSuffix = CodeGeneratorHelpers.ComputeStableMethodSuffix( inv.SourceTypeFullName, inv.CallerFilePath, inv.CallerLineNumber, string.Join("|", inv.ExpressionTexts)); - sb.AppendLine($" return __WhenAnyObservable_{methodSuffix}(objectToMonitor{selectorArg});") + _ = sb.AppendLine($" return __WhenAnyObservable_{methodSuffix}(objectToMonitor{selectorArg});") .AppendLine(" }"); } } - /// - /// Emits the CallerArgumentExpression match condition for a single invocation in the dispatch table. - /// + /// Emits the CallerArgumentExpression match condition for a single invocation in the dispatch table. /// The string builder to append to. /// The invocation info. /// The conditional keyword ("if" or "else if"). @@ -448,23 +426,21 @@ private static void EmitCallerArgExprCondition( string condition, int propCount) { - sb.Append($" {condition} ("); + _ = sb.Append($" {condition} ("); for (var p = 0; p < propCount; p++) { - sb.Append( + _ = sb.Append( $"obs{p + 1}Expression == \"{CodeGeneratorHelpers.EscapeString(inv.ExpressionTexts[p])}\""); if (p < propCount - 1) { - sb.Append(" && "); + _ = sb.Append(" && "); } } - sb.AppendLine(")"); + _ = sb.AppendLine(")"); } - /// - /// Groups invocations by source type and observable type signature for overload generation. - /// + /// Groups invocations by source type and observable type signature for overload generation. /// The first invocation in the group, used for type information. /// All invocations sharing the same type signature. internal sealed record TypeGroup( diff --git a/src/ReactiveUI.Binding.SourceGenerators/Constants.cs b/src/ReactiveUI.Binding.SourceGenerators/Constants.cs index f19f569..c8b2dc9 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Constants.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Constants.cs @@ -10,180 +10,110 @@ namespace ReactiveUI.Binding.SourceGenerators; /// internal static class Constants { - /// - /// Metadata name for . - /// + /// Metadata name for . internal const string INotifyPropertyChangedMetadataName = "System.ComponentModel.INotifyPropertyChanged"; - /// - /// Metadata name for . - /// + /// Metadata name for . internal const string INotifyPropertyChangingMetadataName = "System.ComponentModel.INotifyPropertyChanging"; - /// - /// Metadata name for ReactiveUI's IReactiveObject interface. - /// + /// Metadata name for ReactiveUI's IReactiveObject interface. internal const string IReactiveObjectMetadataName = "ReactiveUI.IReactiveObject"; - /// - /// Metadata name for WPF's DependencyObject base class. - /// + /// Metadata name for WPF's DependencyObject base class. internal const string WpfDependencyObjectMetadataName = "System.Windows.DependencyObject"; - /// - /// Metadata name for WinUI's DependencyObject base class. - /// + /// Metadata name for WinUI's DependencyObject base class. internal const string WinUIDependencyObjectMetadataName = "Microsoft.UI.Xaml.DependencyObject"; - /// - /// Metadata name for Apple's NSObject base class (KVO support). - /// + /// Metadata name for Apple's NSObject base class (KVO support). internal const string NSObjectMetadataName = "Foundation.NSObject"; - /// - /// Metadata name for WinForms' Component base class. - /// + /// Metadata name for WinForms' Component base class. internal const string WinFormsComponentMetadataName = "System.ComponentModel.Component"; - /// - /// Metadata name for Android's View base class. - /// + /// Metadata name for Android's View base class. internal const string AndroidViewMetadataName = "Android.Views.View"; - /// - /// Metadata name for . - /// + /// Metadata name for . internal const string INotifyDataErrorInfoMetadataName = "System.ComponentModel.INotifyDataErrorInfo"; - /// - /// Class name for the runtime API stub extension class emitted as post-initialization output. - /// + /// Class name for the runtime API stub extension class emitted as post-initialization output. internal const string StubExtensionClassName = "ReactiveUIBindingExtensions"; - /// - /// Class name for the scheduler-related extension methods stub class. - /// + /// Class name for the scheduler-related extension methods stub class. internal const string SchedulerExtensionClassName = "ReactiveSchedulerExtensions"; - /// - /// Class name for the generated per-invocation dispatch class. - /// + /// Class name for the generated per-invocation dispatch class. internal const string GeneratedExtensionClassName = "__ReactiveUIGeneratedBindings"; - /// - /// Class name for the generated module-initializer registration class. - /// + /// Class name for the generated module-initializer registration class. internal const string GeneratedBinderRegistrationClassName = "__GeneratedBinderRegistration"; - /// - /// Method name for after-change property observation (WhenChanged). - /// + /// Method name for after-change property observation (WhenChanged). internal const string WhenChangedMethodName = "WhenChanged"; - /// - /// Method name for before-change property observation (WhenChanging). - /// + /// Method name for before-change property observation (WhenChanging). internal const string WhenChangingMethodName = "WhenChanging"; - /// - /// Method name for source-generated one-way binding (BindOneWay). - /// + /// Method name for source-generated one-way binding (BindOneWay). internal const string BindOneWayMethodName = "BindOneWay"; - /// - /// Method name for source-generated two-way binding (BindTwoWay). - /// + /// Method name for source-generated two-way binding (BindTwoWay). internal const string BindTwoWayMethodName = "BindTwoWay"; - /// - /// Method name for ReactiveUI-compatible one-way binding (OneWayBind). - /// + /// Method name for ReactiveUI-compatible one-way binding (OneWayBind). internal const string OneWayBindMethodName = "OneWayBind"; - /// - /// Method name for ReactiveUI-compatible two-way binding (Bind). - /// + /// Method name for ReactiveUI-compatible two-way binding (Bind). internal const string BindMethodName = "Bind"; - /// - /// Method name for multi-property value observation (WhenAnyValue). - /// + /// Method name for multi-property value observation (WhenAnyValue). internal const string WhenAnyValueMethodName = "WhenAnyValue"; - /// - /// Method name for multi-property observation with IObservedChange wrappers (WhenAny). - /// + /// Method name for multi-property observation with IObservedChange wrappers (WhenAny). internal const string WhenAnyMethodName = "WhenAny"; - /// - /// Method name for observable-of-observables merging (WhenAnyObservable). - /// + /// Method name for observable-of-observables merging (WhenAnyObservable). internal const string WhenAnyObservableMethodName = "WhenAnyObservable"; - /// - /// Method name for interaction binding (BindInteraction). - /// + /// Method name for interaction binding (BindInteraction). internal const string BindInteractionMethodName = "BindInteraction"; - /// - /// Method name for command binding (BindCommand). - /// + /// Method name for command binding (BindCommand). internal const string BindCommandMethodName = "BindCommand"; - /// - /// Method name for binding an observable stream to a target property (BindTo). - /// + /// Method name for binding an observable stream to a target property (BindTo). internal const string BindToMethodName = "BindTo"; - /// - /// Metadata name for the open generic IViewFor<T> interface used for view resolution. - /// + /// Metadata name for the open generic IViewFor<T> interface used for view resolution. internal const string IViewForGenericMetadataName = "ReactiveUI.Binding.IViewFor`1"; - /// - /// Metadata name for the ExcludeFromViewRegistrationAttribute used to skip view auto-registration. - /// + /// Metadata name for the ExcludeFromViewRegistrationAttribute used to skip view auto-registration. internal const string ExcludeFromViewRegistrationAttributeMetadataName = "ReactiveUI.Binding.ExcludeFromViewRegistrationAttribute"; - /// - /// Metadata name for the SingleInstanceViewAttribute used for singleton view caching. - /// + /// Metadata name for the SingleInstanceViewAttribute used for singleton view caching. internal const string SingleInstanceViewAttributeMetadataName = "ReactiveUI.Binding.SingleInstanceViewAttribute"; - /// - /// Metadata name for the ViewContractAttribute used for contract-based view registration. - /// + /// Metadata name for the ViewContractAttribute used for contract-based view registration. internal const string ViewContractAttributeMetadataName = "ReactiveUI.Binding.ViewContractAttribute"; - /// - /// Metadata name for the IBindingTypeConverter interface used for custom type conversions. - /// + /// Metadata name for the IBindingTypeConverter interface used for custom type conversions. internal const string IBindingTypeConverterMetadataName = "ReactiveUI.Binding.IBindingTypeConverter"; - /// - /// Metadata name for the open generic IInteraction<TInput, TOutput> interface. - /// + /// Metadata name for the open generic IInteraction<TInput, TOutput> interface. internal const string IInteractionMetadataName = "ReactiveUI.Binding.IInteraction`2"; - /// - /// Metadata name for the System.Windows.Input.ICommand interface. - /// + /// Metadata name for the System.Windows.Input.ICommand interface. internal const string ICommandMetadataName = "System.Windows.Input.ICommand"; - /// - /// Metadata name for the CallerFilePathAttribute used in dispatch stubs. - /// + /// Metadata name for the CallerFilePathAttribute used in dispatch stubs. internal const string CallerFilePathAttributeName = "System.Runtime.CompilerServices.CallerFilePathAttribute"; - /// - /// Metadata name for the CallerLineNumberAttribute used in dispatch stubs. - /// + /// Metadata name for the CallerLineNumberAttribute used in dispatch stubs. internal const string CallerLineNumberAttributeName = "System.Runtime.CompilerServices.CallerLineNumberAttribute"; - /// - /// Metadata name for the CallerArgumentExpressionAttribute used in dispatch stubs for C# 10+ projects. - /// + /// Metadata name for the CallerArgumentExpressionAttribute used in dispatch stubs for C# 10+ projects. internal const string CallerArgumentExpressionAttributeMetadataName = "System.Runtime.CompilerServices.CallerArgumentExpressionAttribute"; } diff --git a/src/ReactiveUI.Binding.SourceGenerators/DiagnosticWarnings.cs b/src/ReactiveUI.Binding.SourceGenerators/DiagnosticWarnings.cs index cdb4838..8a2e20e 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/DiagnosticWarnings.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/DiagnosticWarnings.cs @@ -18,9 +18,7 @@ internal static class DiagnosticWarnings /// The diagnostic category shared by all RXUIBIND descriptors. internal const string UsageCategory = "Usage"; - /// - /// RXUIBIND001: Expression must be inline lambda for compile-time optimization. - /// + /// RXUIBIND001: Expression must be inline lambda for compile-time optimization. internal static readonly DiagnosticDescriptor NonInlineLambda = new( "RXUIBIND001", "Expression must be inline lambda", @@ -30,9 +28,7 @@ internal static class DiagnosticWarnings true, NoneInlineLambdaDescription); - /// - /// RXUIBIND002: Type has no observable properties. - /// + /// RXUIBIND002: Type has no observable properties. internal static readonly DiagnosticDescriptor NoObservableProperties = new( "RXUIBIND002", "Type has no observable properties", @@ -42,9 +38,7 @@ internal static class DiagnosticWarnings true, NoObservablePropertiesDescription); - /// - /// RXUIBIND003: Expression contains private/protected member. - /// + /// RXUIBIND003: Expression contains private/protected member. internal static readonly DiagnosticDescriptor PrivateMember = new( "RXUIBIND003", "Expression contains private or protected member", @@ -54,9 +48,7 @@ internal static class DiagnosticWarnings true, PrivateMemberDescription); - /// - /// RXUIBIND004: Type does not support before-change notifications. - /// + /// RXUIBIND004: Type does not support before-change notifications. internal static readonly DiagnosticDescriptor NoBeforeChangeSupport = new( "RXUIBIND004", "Type does not support before-change notifications", @@ -66,9 +58,7 @@ internal static class DiagnosticWarnings true, NoBeforeChangeSupportDescription); - /// - /// RXUIBIND005: Source type implements INotifyDataErrorInfo. - /// + /// RXUIBIND005: Source type implements INotifyDataErrorInfo. internal static readonly DiagnosticDescriptor ValidationNotGenerated = new( "RXUIBIND005", "Validation binding not generated", @@ -78,9 +68,7 @@ internal static class DiagnosticWarnings true, ValidationNotGeneratedDescription); - /// - /// RXUIBIND006: Expression contains unsupported path segment (indexer, field, or method call). - /// + /// RXUIBIND006: Expression contains unsupported path segment (indexer, field, or method call). internal static readonly DiagnosticDescriptor UnsupportedPathSegment = new( "RXUIBIND006", "Expression contains unsupported path segment", @@ -90,9 +78,7 @@ internal static class DiagnosticWarnings true, UnsupportedPathSegmentDescription); - /// - /// RXUIBIND007: BindCommand control has no bindable event. - /// + /// RXUIBIND007: BindCommand control has no bindable event. internal static readonly DiagnosticDescriptor NoBindableEvent = new( "RXUIBIND007", "Control has no bindable event", @@ -102,9 +88,7 @@ internal static class DiagnosticWarnings true, NoBindableEventDescription); - /// - /// RXUIBIND008: Property does not implement IInteraction. - /// + /// RXUIBIND008: Property does not implement IInteraction. internal static readonly DiagnosticDescriptor InvalidInteractionType = new( "RXUIBIND008", "Property is not an IInteraction", @@ -116,39 +100,39 @@ internal static class DiagnosticWarnings /// The string description of the none inline lambda. private const string NoneInlineLambdaDescription = - "The source generator can only optimize inline lambda expressions (e.g., x => x.Property). " + - "Variable references, method calls, or other non-inline expressions will fall back to runtime expression-tree analysis."; + "The source generator can only optimize inline lambda expressions (e.g., x => x.Property). " + + "Variable references, method calls, or other non-inline expressions will fall back to runtime expression-tree analysis."; /// The string description of the no observable properties warning. private const string NoObservablePropertiesDescription = - "The type used in the binding expression does not implement INotifyPropertyChanged, INotifyPropertyChanging, " + - "IReactiveObject, or inherit from any known observable base type."; + "The type used in the binding expression does not implement INotifyPropertyChanged, INotifyPropertyChanging, " + + "IReactiveObject, or inherit from any known observable base type."; /// The string description of the private member warning. private const string PrivateMemberDescription = - "The source generator generates extension methods which cannot access private or protected members. " + - "The binding will fall back to runtime reflection."; + "The source generator generates extension methods which cannot access private or protected members. " + + "The binding will fall back to runtime reflection."; /// The string description of the no before-change support warning. private const string NoBeforeChangeSupportDescription = - "The notification mechanism for this type does not provide before-change events. " + - "WPF DependencyObjects, WinForms Components, and Android Views only support after-change notifications."; + "The notification mechanism for this type does not provide before-change events. " + + "WPF DependencyObjects, WinForms Components, and Android Views only support after-change notifications."; /// The string description of the validation not generated warning. private const string ValidationNotGeneratedDescription = - "The generated bindings handle value binding only. " + - "Validation state propagation from INotifyDataErrorInfo requires the runtime ReactiveUI binding engine " + - "or a manual ErrorsChanged subscription."; + "The generated bindings handle value binding only. " + + "Validation state propagation from INotifyDataErrorInfo requires the runtime ReactiveUI binding engine " + + "or a manual ErrorsChanged subscription."; /// The string description of the unsupported path segment warning. private const string UnsupportedPathSegmentDescription = - "The source generator can only observe simple property access chains (e.g., x => x.Foo.Bar). " + - "Indexers, fields, and method calls in the path require runtime expression analysis."; + "The source generator can only observe simple property access chains (e.g., x => x.Foo.Bar). " + + "Indexers, fields, and method calls in the path require runtime expression analysis."; /// The string description of the no bindable event warning. private const string NoBindableEventDescription = - "The source generator could not find a default event to bind on the control type. " + - "Specify the 'toEvent' parameter explicitly."; + "The source generator could not find a default event to bind on the control type. " + + "Specify the 'toEvent' parameter explicitly."; /// The string description of the invalid interaction type warning. private const string InvalidInteractionTypeDescription = diff --git a/src/ReactiveUI.Binding.SourceGenerators/Generators/RegistrationGenerator.cs b/src/ReactiveUI.Binding.SourceGenerators/Generators/RegistrationGenerator.cs index d6141de..cca67a1 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Generators/RegistrationGenerator.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Generators/RegistrationGenerator.cs @@ -15,13 +15,11 @@ namespace ReactiveUI.Binding.SourceGenerators.Generators; /// internal static class RegistrationGenerator { - /// - /// Generates the consolidated registration output: all per-kind binder classes. - /// + /// Generates the consolidated registration output: all per-kind binder classes. /// The source production context. /// All detected observable type infos across all notification kinds. /// The consumer compilation's language-feature and generation-option snapshot. - internal static void Generate(SourceProductionContext context, ImmutableArray allTypes, LanguageFeatures features) + internal static void Generate(in SourceProductionContext context, ImmutableArray allTypes, LanguageFeatures features) { if (!Helpers.ExtractorValidation.HasItems(allTypes)) { @@ -32,17 +30,19 @@ internal static void Generate(SourceProductionContext context, ImmutableArray(); for (var i = 0; i < allTypes.Length; i++) { - uniqueKinds.Add(allTypes[i].ObservationKind); + _ = uniqueKinds.Add(allTypes[i].ObservationKind); } - var sb = new StringBuilder(1_024 + (allTypes.Length * 128)); + var sb = new StringBuilder( + CodeGeneration.CodeGeneratorHelpers.PerInvocationBufferCapacity + + (allTypes.Length * CodeGeneration.CodeGeneratorHelpers.FragmentBufferCapacity)); CodeGeneration.CodeGeneratorHelpers.AppendGeneratedFileMarkers(sb, features.EmitGeneratedCodeMarkers); if (features.SupportsNullable) { - sb.AppendLine("#nullable enable"); + _ = sb.AppendLine("#nullable enable"); } - sb.AppendLine(""" + _ = sb.AppendLine(""" namespace ReactiveUI.Binding.Generated { @@ -64,10 +64,10 @@ internal static void Initialize() foreach (var kind in uniqueKinds) { - sb.AppendLine($" // Detected types for kind: {kind}"); + _ = sb.AppendLine($" // Detected types for kind: {kind}"); } - sb.AppendLine(""" + _ = sb.AppendLine(""" } } } diff --git a/src/ReactiveUI.Binding.SourceGenerators/Generators/ViewLocatorDispatchGenerator.cs b/src/ReactiveUI.Binding.SourceGenerators/Generators/ViewLocatorDispatchGenerator.cs index 8b0aed9..97a3668 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Generators/ViewLocatorDispatchGenerator.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Generators/ViewLocatorDispatchGenerator.cs @@ -17,9 +17,7 @@ namespace ReactiveUI.Binding.SourceGenerators.Generators; /// internal static class ViewLocatorDispatchGenerator { - /// - /// The identifier prefix used for the per-view resolver methods emitted in the generated source. - /// + /// The identifier prefix used for the per-view resolver methods emitted in the generated source. private const string ResolverMethodNamePrefix = "__ResolveView_"; /// @@ -29,7 +27,7 @@ internal static class ViewLocatorDispatchGenerator /// The incremental generator initialization context. /// The consumer compilation's C# language-feature snapshot. internal static void Register( - IncrementalGeneratorInitializationContext context, + in IncrementalGeneratorInitializationContext context, IncrementalValueProvider languageFeatures) { // Reuse Pipeline A's class-with-base-list predicate @@ -48,13 +46,11 @@ internal static void Register( static (ctx, data) => Generate(ctx, data.Left, data.Right)); } - /// - /// Generates the ViewDispatch.g.cs source file from collected view registrations. - /// + /// Generates the ViewDispatch.g.cs source file from collected view registrations. /// The source production context. /// All detected view registration infos. /// The consumer compilation's language-feature and generation-option snapshot. - internal static void Generate(SourceProductionContext context, ImmutableArray registrations, LanguageFeatures features) + internal static void Generate(in SourceProductionContext context, ImmutableArray registrations, LanguageFeatures features) { if (!ExtractorValidation.HasItems(registrations)) { @@ -64,14 +60,15 @@ internal static void Generate(SourceProductionContext context, ImmutableArray - /// Deduplicates view registrations by (view model fully qualified name, contract) pair. - /// + /// Deduplicates view registrations by (view model fully qualified name, contract) pair. /// The raw registrations. /// A deduplicated list of registrations. private static List Deduplicate(ImmutableArray registrations) @@ -91,69 +88,24 @@ private static List Deduplicate(ImmutableArray - /// Generates the full source output into the StringBuilder. - /// + /// Generates the full source output into the StringBuilder. /// The string builder to write to. /// The deduplicated registrations. /// The consumer compilation's language-feature and generation-option snapshot. private static void GenerateSource(StringBuilder sb, List registrations, LanguageFeatures features) { var supportsNullable = features.SupportsNullable; - var nullable = supportsNullable ? "?" : string.Empty; - CodeGeneration.CodeGeneratorHelpers.AppendGeneratedFileMarkers(sb, features.EmitGeneratedCodeMarkers); - if (supportsNullable) - { - sb.AppendLine("#nullable enable"); - } - - sb.Append(""" - - namespace ReactiveUI.Binding - { - internal static partial class __ReactiveUIGeneratedBindings - { - """); + EmitFileHeader(sb, features); // Singleton cache fields for [SingleInstanceView] views EmitSingletonFields(sb, registrations); - // Static field initializer to trigger registration - sb.AppendLine().Append($$""" - /// - /// Triggers view dispatch registration when the generated bindings class is loaded. - /// - private static readonly bool __viewDispatchRegistered = __RegisterViewDispatch(); - - /// - /// Registers the source-generated view dispatch function with - /// . - /// Called once via static field initializer when this class is first accessed. - /// - /// Always returns . - private static bool __RegisterViewDispatch() - { - global::ReactiveUI.Binding.DefaultViewLocator.SetGeneratedViewDispatch( - __TryResolveView); - return true; - } - - /// - /// Compile-time generated type-switch dispatch for view resolution. - /// Attempts to resolve a view for the given view model instance without reflection. - /// - /// The view model instance to resolve a view for. - /// The contract string (empty string for default). - /// The resolved view, or if no generated mapping exists. - private static global::ReactiveUI.Binding.IViewFor{{nullable}} __TryResolveView( - object instance, string contract) - { - """); + EmitRegistrationHook(sb, supportsNullable ? "?" : string.Empty); // Emit the per-view-model dispatch branches into the dispatch function body. EmitDispatchBranches(sb, registrations); - sb.AppendLine().Append(""" + _ = sb.AppendLine().Append(""" // No compile-time mapping found; fall back to runtime resolution. return null; @@ -166,16 +118,72 @@ private static bool __RegisterViewDispatch() GenerateResolverMethod(sb, registrations[i], i, supportsNullable); } - sb.AppendLine().Append(""" + _ = sb.AppendLine().Append(""" } } """); } + /// Emits the generated-file markers, nullable directive, and the enclosing namespace and class declarations. + /// The string builder to write to. + /// The consumer compilation's language-feature and generation-option snapshot. + private static void EmitFileHeader(StringBuilder sb, LanguageFeatures features) + { + CodeGeneration.CodeGeneratorHelpers.AppendGeneratedFileMarkers(sb, features.EmitGeneratedCodeMarkers); + if (features.SupportsNullable) + { + _ = sb.AppendLine("#nullable enable"); + } + + _ = sb.Append(""" + + namespace ReactiveUI.Binding + { + internal static partial class __ReactiveUIGeneratedBindings + { + """); + } + /// - /// Emits the singleton cache fields for [SingleInstanceView] views with a parameterless constructor. + /// Emits the static field initializer that registers the dispatch function on class load, and + /// the signature of the dispatch function itself. /// /// The string builder to write to. + /// The nullable annotation to emit, or an empty string when unsupported. + private static void EmitRegistrationHook(StringBuilder sb, string nullable) => + sb.AppendLine().Append($$""" + /// + /// Triggers view dispatch registration when the generated bindings class is loaded. + /// + private static readonly bool __viewDispatchRegistered = __RegisterViewDispatch(); + + /// + /// Registers the source-generated view dispatch function with + /// . + /// Called once via static field initializer when this class is first accessed. + /// + /// Always returns . + private static bool __RegisterViewDispatch() + { + global::ReactiveUI.Binding.DefaultViewLocator.SetGeneratedViewDispatch( + __TryResolveView); + return true; + } + + /// + /// Compile-time generated type-switch dispatch for view resolution. + /// Attempts to resolve a view for the given view model instance without reflection. + /// + /// The view model instance to resolve a view for. + /// The contract string (empty string for default). + /// The resolved view, or if no generated mapping exists. + private static global::ReactiveUI.Binding.IViewFor{{nullable}} __TryResolveView( + object instance, string contract) + { + """); + + /// Emits the singleton cache fields for [SingleInstanceView] views with a parameterless constructor. + /// The string builder to write to. /// The deduplicated registrations. private static void EmitSingletonFields(StringBuilder sb, List registrations) { @@ -184,7 +192,7 @@ private static void EmitSingletonFields(StringBuilder sb, List /// Cached singleton instance for (marked with [SingleInstanceView]). /// @@ -204,27 +212,27 @@ private static void EmitSingletonFields(StringBuilder sb, ListThe deduplicated registrations. private static void EmitDispatchBranches(StringBuilder sb, List registrations) { - var vmOrder = new List(registrations.Count); - var vmGroupIndices = new Dictionary>(registrations.Count); + var viewModelOrder = new List(registrations.Count); + var viewModelGroupIndices = new Dictionary>(registrations.Count); for (var i = 0; i < registrations.Count; i++) { - var vmFqn = registrations[i].ViewModelFullyQualifiedName; - if (!vmGroupIndices.TryGetValue(vmFqn, out var indices)) + var viewModelFqn = registrations[i].ViewModelFullyQualifiedName; + if (!viewModelGroupIndices.TryGetValue(viewModelFqn, out var indices)) { indices = []; - vmGroupIndices[vmFqn] = indices; - vmOrder.Add(vmFqn); + viewModelGroupIndices[viewModelFqn] = indices; + viewModelOrder.Add(viewModelFqn); } indices.Add(i); } - for (var g = 0; g < vmOrder.Count; g++) + for (var g = 0; g < viewModelOrder.Count; g++) { - var vmFqn = vmOrder[g]; - var indices = vmGroupIndices[vmFqn]; + var viewModelFqn = viewModelOrder[g]; + var indices = viewModelGroupIndices[viewModelFqn]; - sb.AppendLine(); + _ = sb.AppendLine(); if (indices.Count == 1) { @@ -234,7 +242,7 @@ private static void EmitDispatchBranches(StringBuilder sb, List {{reg.ViewFullyQualifiedName}} [contract: {{escapedLiteral}}] if (instance is {{reg.ViewModelFullyQualifiedName}}) { @@ -270,7 +278,7 @@ private static void EmitSingleRegistrationDispatch( } else { - sb.Append($$""" + _ = sb.Append($$""" // {{reg.ViewModelFullyQualifiedName}} -> {{reg.ViewFullyQualifiedName}} if (instance is {{reg.ViewModelFullyQualifiedName}}) { @@ -286,17 +294,17 @@ private static void EmitSingleRegistrationDispatch( /// /// The string builder. /// All registrations. - /// The fully qualified VM type name. + /// The fully qualified VM type name. /// The registration indices for this VM type. private static void EmitGroupedDispatch( StringBuilder sb, List registrations, - string vmFqn, + string viewModelFqn, List indices) { - sb.Append($$""" - // {{vmFqn}} — multiple views - if (instance is {{vmFqn}}) + _ = sb.Append($$""" + // {{viewModelFqn}} — multiple views + if (instance is {{viewModelFqn}}) { """); @@ -309,7 +317,7 @@ private static void EmitGroupedDispatch( { var escapedLiteral = SymbolDisplay.FormatLiteral(reg.Contract, true); var resolverMethodName = ResolverMethodNamePrefix + idx; - sb.AppendLine().Append($$""" + _ = sb.AppendLine().Append($$""" // -> {{reg.ViewFullyQualifiedName}} [contract: {{escapedLiteral}}] if (contract == {{escapedLiteral}}) { @@ -327,7 +335,7 @@ private static void EmitGroupedDispatch( if (reg.Contract is null) { var resolverMethodName = ResolverMethodNamePrefix + idx; - sb.AppendLine().Append($$""" + _ = sb.AppendLine().Append($$""" // -> {{reg.ViewFullyQualifiedName}} (default) return {{resolverMethodName}}(contract); """); @@ -335,14 +343,12 @@ private static void EmitGroupedDispatch( } } - sb.AppendLine().Append(""" + _ = sb.AppendLine().Append(""" } """); } - /// - /// Generates a per-view-model resolver method. - /// + /// Generates a per-view-model resolver method. /// The string builder. /// The view registration info. /// The unique index for method naming. @@ -361,7 +367,7 @@ private static void GenerateResolverMethod(StringBuilder sb, ViewRegistrationInf (false, false) => " /// Service locator only — no direct construction available." }; - sb.AppendLine().Append($$""" + _ = sb.AppendLine().Append($$""" /// /// Resolves a view for . @@ -384,44 +390,54 @@ private static void GenerateResolverMethod(StringBuilder sb, ViewRegistrationInf } """); - if (reg.HasParameterlessConstructor) - { - if (reg.IsSingleInstance) - { - var fieldName = "__singletonView_" + index; - sb.Append($$""" - - // Fallback: singleton construction ({{reg.ViewFullyQualifiedName}} has [SingleInstanceView]). - if ({{fieldName}} == null) - { - System.Threading.Interlocked.CompareExchange( - ref {{fieldName}}, - new {{reg.ViewFullyQualifiedName}}(), - null); - } - - return {{fieldName}}; - """); - } - else - { - sb.Append($$""" + EmitResolverFallback(sb, reg, index); - // Fallback: direct construction ({{reg.ViewFullyQualifiedName}} has a parameterless constructor). - return new {{reg.ViewFullyQualifiedName}}(); - """); - } - } - else + _ = sb.AppendLine().Append(""" + } + """); + } + + /// + /// Emits what the resolver does when the service locator has nothing registered: construct the + /// view directly, cache a singleton, or give up. + /// + /// The string builder to append to. + /// The view registration being emitted. + /// The registration's index, used to name the singleton field. + private static void EmitResolverFallback(StringBuilder sb, ViewRegistrationInfo reg, int index) + { + if (!reg.HasParameterlessConstructor) { - sb.Append(""" + _ = sb.Append(""" return null; """); + return; } - sb.AppendLine().Append(""" - } - """); + if (!reg.IsSingleInstance) + { + _ = sb.Append($$""" + + // Fallback: direct construction ({{reg.ViewFullyQualifiedName}} has a parameterless constructor). + return new {{reg.ViewFullyQualifiedName}}(); + """); + return; + } + + var fieldName = $"__singletonView_{index}"; + _ = sb.Append($$""" + + // Fallback: singleton construction ({{reg.ViewFullyQualifiedName}} has [SingleInstanceView]). + if ({{fieldName}} == null) + { + System.Threading.Interlocked.CompareExchange( + ref {{fieldName}}, + new {{reg.ViewFullyQualifiedName}}(), + null); + } + + return {{fieldName}}; + """); } } diff --git a/src/ReactiveUI.Binding.SourceGenerators/Helpers/BindToExtractor.cs b/src/ReactiveUI.Binding.SourceGenerators/Helpers/BindToExtractor.cs index 5582a18..7e82ead 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Helpers/BindToExtractor.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Helpers/BindToExtractor.cs @@ -14,14 +14,10 @@ namespace ReactiveUI.Binding.SourceGenerators.Helpers; /// internal static class BindToExtractor { - /// - /// The minimum number of arguments a BindTo invocation must have (target, property). - /// + /// The minimum number of arguments a BindTo invocation must have (target, property). private const int MinimumBindToArgumentCount = 2; - /// - /// Pipeline B transform: extracts from a BindTo invocation. - /// + /// Pipeline B transform: extracts from a BindTo invocation. /// The generator syntax context. /// Cancellation token. /// A POCO, or null if the invocation is not analyzable. @@ -32,7 +28,7 @@ internal static class BindToExtractor var semanticModel = context.SemanticModel; var methodSymbol = ExtractorValidation.ExtractMethodSymbol(semanticModel.GetSymbolInfo(invocation, ct)); - if (methodSymbol == null) + if (methodSymbol is null) { return null; } @@ -52,27 +48,27 @@ internal static class BindToExtractor // The source value type is the T in the receiver's IObservable. var receiverType = semanticModel.GetTypeInfo(memberAccess.Expression, ct).Type; var sourceValueType = GetObservableValueType(receiverType); - if (sourceValueType == null) + if (sourceValueType is null) { return null; } var targetPropertyArg = args[1].Expression; var targetPropertyPath = SyntaxHelpers.ExtractPropertyPathFromLambda(targetPropertyArg, semanticModel, ct); - if (targetPropertyPath == null || targetPropertyPath.Length == 0) + if (targetPropertyPath is null || targetPropertyPath.Length == 0) { return null; } var targetTypeName = ExtractorValidation.GetTypeDisplayName(semanticModel.GetTypeInfo(args[0].Expression, ct).Type); - if (targetTypeName == null) + if (targetTypeName is null) { return null; } var sourceValueTypeFullName = sourceValueType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); - var targetPropertyTypeFullName = targetPropertyPath[targetPropertyPath.Length - 1].PropertyTypeFullName; + var targetPropertyTypeFullName = targetPropertyPath[^1].PropertyTypeFullName; DetectConversionParameters(methodSymbol, out var hasConversionHint, out var hasConverterOverride); diff --git a/src/ReactiveUI.Binding.SourceGenerators/Helpers/BindingExtractor.cs b/src/ReactiveUI.Binding.SourceGenerators/Helpers/BindingExtractor.cs index e081d06..4a660f8 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Helpers/BindingExtractor.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Helpers/BindingExtractor.cs @@ -8,9 +8,7 @@ namespace ReactiveUI.Binding.SourceGenerators.Helpers; -/// -/// Extracts BindingInvocationInfo from BindOneWay, BindTwoWay, OneWayBind, and Bind invocations. -/// +/// Extracts BindingInvocationInfo from BindOneWay, BindTwoWay, OneWayBind, and Bind invocations. internal static class BindingExtractor { /// @@ -19,9 +17,7 @@ internal static class BindingExtractor /// private const int MinimumBindingArgumentCount = 3; - /// - /// Pipeline B transform: extracts BindingInvocationInfo from a BindOneWay/BindTwoWay/OneWayBind/Bind invocation. - /// + /// Pipeline B transform: extracts BindingInvocationInfo from a BindOneWay/BindTwoWay/OneWayBind/Bind invocation. /// The generator syntax context. /// Cancellation token. /// A BindingInvocationInfo POCO, or null if the invocation is not analyzable. @@ -33,7 +29,7 @@ internal static class BindingExtractor var semanticModel = context.SemanticModel; var methodSymbol = ExtractorValidation.ExtractMethodSymbol(semanticModel.GetSymbolInfo(invocation, ct)); - if (methodSymbol == null) + if (methodSymbol is null) { return null; } @@ -58,22 +54,13 @@ internal static class BindingExtractor var sourcePropertyPath = SyntaxHelpers.ExtractPropertyPathFromLambda(sourcePropertyArg, semanticModel, ct); var targetPropertyPath = SyntaxHelpers.ExtractPropertyPathFromLambda(targetPropertyArg, semanticModel, ct); - if (sourcePropertyPath == null || targetPropertyPath == null) + if (sourcePropertyPath is null || targetPropertyPath is null) { return null; } - // Get types - var receiverTypeName = InvalidOperationExceptionHelper.EnsureNotNull( - ExtractorValidation.GetTypeDisplayName(semanticModel.GetTypeInfo(memberAccess.Expression, ct).Type), - "receiver type display name"); - - var firstArgTypeName = InvalidOperationExceptionHelper.EnsureNotNull( - ExtractorValidation.GetTypeDisplayName(semanticModel.GetTypeInfo(args[0].Expression, ct).Type), - "first argument type display name"); - - var sourcePropertyTypeFullName = sourcePropertyPath[sourcePropertyPath.Length - 1].PropertyTypeFullName; - var targetPropertyTypeFullName = targetPropertyPath[targetPropertyPath.Length - 1].PropertyTypeFullName; + var (sourceTypeFullName, targetTypeFullName) = + ResolveBindingSides(memberAccess, args, methodName, semanticModel, ct); DetectBindingParameters( methodSymbol, @@ -81,35 +68,55 @@ internal static class BindingExtractor out var hasScheduler, out var hasConverterOverride); - var filePath = invocation.SyntaxTree.FilePath; - var lineNumber = invocation.GetLocation().GetLineSpan().StartLinePosition.Line + 1; - var sourceExpressionText = - CodeGeneration.CodeGeneratorHelpers.NormalizeLambdaText(sourcePropertyArg.ToString()); - var targetExpressionText = - CodeGeneration.CodeGeneratorHelpers.NormalizeLambdaText(targetPropertyArg.ToString()); - - var isViewFirst = methodName is Constants.OneWayBindMethodName or Constants.BindMethodName; - var sourceTypeFullName = isViewFirst ? firstArgTypeName : receiverTypeName; - var targetTypeFullName = isViewFirst ? receiverTypeName : firstArgTypeName; - return new( - filePath, - lineNumber, + invocation.SyntaxTree.FilePath, + invocation.GetLocation().GetLineSpan().StartLinePosition.Line + 1, sourceTypeFullName, new(sourcePropertyPath), targetTypeFullName, new(targetPropertyPath), - sourcePropertyTypeFullName, - targetPropertyTypeFullName, + sourcePropertyPath[^1].PropertyTypeFullName, + targetPropertyPath[^1].PropertyTypeFullName, hasConversion, hasScheduler, isTwoWay, methodName, - sourceExpressionText, - targetExpressionText, + CodeGeneration.CodeGeneratorHelpers.NormalizeLambdaText(sourcePropertyArg.ToString()), + CodeGeneration.CodeGeneratorHelpers.NormalizeLambdaText(targetPropertyArg.ToString()), hasConverterOverride); } + /// + /// Resolves which side of the binding is the source and which is the target. The view-first + /// overloads take the view as the receiver, so the roles are swapped relative to the others. + /// + /// The member access the invocation hangs off. + /// The invocation arguments. + /// The invoked method name. + /// The semantic model. + /// Cancellation token. + /// The fully qualified source and target type names. + private static (string SourceTypeFullName, string TargetTypeFullName) ResolveBindingSides( + MemberAccessExpressionSyntax memberAccess, + SeparatedSyntaxList args, + string methodName, + SemanticModel semanticModel, + CancellationToken ct) + { + var receiverTypeName = InvalidOperationExceptionHelper.EnsureNotNull( + ExtractorValidation.GetTypeDisplayName(semanticModel.GetTypeInfo(memberAccess.Expression, ct).Type), + "receiver type display name"); + + var firstArgTypeName = InvalidOperationExceptionHelper.EnsureNotNull( + ExtractorValidation.GetTypeDisplayName(semanticModel.GetTypeInfo(args[0].Expression, ct).Type), + "first argument type display name"); + + var isViewFirst = methodName is Constants.OneWayBindMethodName or Constants.BindMethodName; + return isViewFirst + ? (firstArgTypeName, receiverTypeName) + : (receiverTypeName, firstArgTypeName); + } + /// /// Scans the method parameters to detect conversion, scheduler, and converter-override /// capabilities of the binding overload. @@ -130,7 +137,7 @@ private static void DetectBindingParameters( foreach (var parameter in methodSymbol.Parameters) { - if (parameter.Name is "conversionFunc" or "sourceToTargetConv" or "selector" or "vmToViewConverter") + if (parameter.Name is "conversionFunc" or "sourceToTargetConv" or "selector" or "vmToViewConverter" or "viewModelToViewConverter") { hasConversion = true; } diff --git a/src/ReactiveUI.Binding.SourceGenerators/Helpers/CommandExtractor.cs b/src/ReactiveUI.Binding.SourceGenerators/Helpers/CommandExtractor.cs index f4e2dee..8989a18 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Helpers/CommandExtractor.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Helpers/CommandExtractor.cs @@ -8,26 +8,16 @@ namespace ReactiveUI.Binding.SourceGenerators.Helpers; -/// -/// Extracts values from BindCommand -/// invocations and provides compile-time command property detection helpers. -/// +/// Extracts values from BindCommand invocations and provides compile-time command property detection helpers. internal static class CommandExtractor { - /// - /// The minimum number of arguments a BindCommand invocation must have - /// (view model, property name, control name). - /// + /// The minimum number of arguments a BindCommand invocation must have (view model, property name, control name). private const int MinimumBindCommandArgumentCount = 3; - /// - /// The argument index at which optional withParameter lambdas may start. - /// + /// The argument index at which optional withParameter lambdas may start. private const int WithParameterSearchStartIndex = 3; - /// - /// Extracts generator input metadata from a recognized BindCommand invocation. - /// + /// Extracts generator input metadata from a recognized BindCommand invocation. /// /// The generator syntax context whose node is expected to be an invocation expression. /// @@ -46,7 +36,7 @@ internal static class CommandExtractor var semanticModel = context.SemanticModel; var methodSymbol = ExtractorValidation.ExtractMethodSymbol(semanticModel.GetSymbolInfo(invocation, ct)); - if (methodSymbol == null) + if (methodSymbol is null) { return null; } @@ -63,7 +53,7 @@ internal static class CommandExtractor // Extract command property path (2nd argument: propertyName) var commandPropertyArg = args[1].Expression; var commandPropertyPath = SyntaxHelpers.ExtractPropertyPathFromLambda(commandPropertyArg, semanticModel, ct); - if (commandPropertyPath == null) + if (commandPropertyPath is null) { return null; } @@ -71,53 +61,24 @@ internal static class CommandExtractor // Extract control property path (3rd argument: controlName) var controlPropertyArg = args[2].Expression; var controlPropertyPath = SyntaxHelpers.ExtractPropertyPathFromLambda(controlPropertyArg, semanticModel, ct); - if (controlPropertyPath == null) + if (controlPropertyPath is null) { return null; } - // Get types - var viewTypeFullName = InvalidOperationExceptionHelper.EnsureNotNull( - ExtractorValidation.GetTypeDisplayName(semanticModel.GetTypeInfo(memberAccess.Expression, ct).Type), - "view type display name"); - - var viewModelTypeFullName = InvalidOperationExceptionHelper.EnsureNotNull( - ExtractorValidation.GetTypeDisplayName(semanticModel.GetTypeInfo(args[0].Expression, ct).Type), - "view model type display name"); - - var commandTypeFullName = commandPropertyPath[commandPropertyPath.Length - 1].PropertyTypeFullName; - var controlTypeFullName = controlPropertyPath[controlPropertyPath.Length - 1].PropertyTypeFullName; + var (viewTypeFullName, viewModelTypeFullName) = ResolveBindCommandSides(memberAccess, args, semanticModel, ct); + var commandTypeFullName = commandPropertyPath[^1].PropertyTypeFullName; + var controlTypeFullName = controlPropertyPath[^1].PropertyTypeFullName; // Determine parameter overload (Expression vs IObservable withParameter) var parameterOverload = DetectParameterOverload(methodSymbol, args, semanticModel, ct); - // Resolve event name from toEvent string literal or default event detection - var resolvedEventName = ResolveExplicitEventName(methodSymbol, args, semanticModel, ct); - - // Resolve control leaf type for property/event detection - var controlLeafType = SymbolHelpers.ResolveNamedType( - controlPropertyPath[controlPropertyPath.Length - 1], - semanticModel, - controlPropertyArg, - ct); - - var resolvedEventArgsTypeFullName = ResolveEventArgsTypeFullName( - controlLeafType, - ref resolvedEventName); - - // Detect command-property and enabled-property capabilities on the control - var capabilities = DetectControlCapabilities(controlLeafType); - - var filePath = invocation.SyntaxTree.FilePath; - var lineNumber = invocation.GetLocation().GetLineSpan().StartLinePosition.Line + 1; - var commandExpressionText = - CodeGeneration.CodeGeneratorHelpers.NormalizeLambdaText(commandPropertyArg.ToString()); - var controlExpressionText = - CodeGeneration.CodeGeneratorHelpers.NormalizeLambdaText(controlPropertyArg.ToString()); + var (resolvedEventName, resolvedEventArgsTypeFullName, capabilities) = + ResolveControlBinding(methodSymbol, args, controlPropertyPath, controlPropertyArg, semanticModel, ct); return new( - filePath, - lineNumber, + invocation.SyntaxTree.FilePath, + invocation.GetLocation().GetLineSpan().StartLinePosition.Line + 1, viewTypeFullName, viewModelTypeFullName, new(commandPropertyPath), @@ -128,21 +89,19 @@ internal static class CommandExtractor parameterOverload.HasExpressionParameter, parameterOverload.ParameterTypeFullName, parameterOverload.ParameterIsReferenceType, - parameterOverload.ParameterPropertyPath != null ? new EquatableArray(parameterOverload.ParameterPropertyPath) : null, + parameterOverload.ParameterPropertyPath, resolvedEventName, resolvedEventArgsTypeFullName, Constants.BindCommandMethodName, - commandExpressionText, - controlExpressionText, + CodeGeneration.CodeGeneratorHelpers.NormalizeLambdaText(commandPropertyArg.ToString()), + CodeGeneration.CodeGeneratorHelpers.NormalizeLambdaText(controlPropertyArg.ToString()), parameterOverload.ParameterExpressionText, capabilities.HasCommand, capabilities.HasCommandParameter, capabilities.HasEnabled); } - /// - /// Searches invocation arguments for a valid withParameter lambda expression. - /// + /// Searches invocation arguments for a valid withParameter lambda expression. /// The argument list from the invocation. /// The semantic model used to resolve lambda property paths. /// The token used to cancel semantic model operations. @@ -159,11 +118,11 @@ internal static (PropertyPathSegment[] PropertyPath, string TypeFullName, string for (var a = WithParameterSearchStartIndex; a < args.Count; a++) { var paramPath = SyntaxHelpers.ExtractPropertyPathFromLambda(args[a].Expression, semanticModel, ct); - if (paramPath != null) + if (paramPath is not null) { return ( paramPath, - paramPath[paramPath.Length - 1].PropertyTypeFullName, + paramPath[^1].PropertyTypeFullName, CodeGeneration.CodeGeneratorHelpers.NormalizeLambdaText(args[a].Expression.ToString())); } } @@ -221,10 +180,7 @@ internal static bool HasCommandProperties(INamedTypeSymbol controlType, out bool return hasCommand; } - /// - /// Checks if a control type has a settable Enabled property (bool). - /// Walks the type hierarchy. - /// + /// Checks if a control type has a settable Enabled property (bool). Walks the type hierarchy. /// The control type symbol to inspect. /// /// if the type or one of its base types has a public settable @@ -269,17 +225,65 @@ internal static bool IsToEventArgument( int parameterIndex) { var nameColon = argument.NameColon; - if (nameColon != null) - { - return nameColon.Name.Identifier.Text == "toEvent"; - } + return nameColon is not null ? nameColon.Name.Identifier.Text == "toEvent" : argumentIndex == parameterIndex; + } - return argumentIndex == parameterIndex; + /// Resolves the view and view model types the invocation binds between. + /// The member access the invocation hangs off. + /// The invocation arguments. + /// The semantic model. + /// Cancellation token. + /// The fully qualified view and view model type names. + private static (string ViewTypeFullName, string ViewModelTypeFullName) ResolveBindCommandSides( + MemberAccessExpressionSyntax memberAccess, + SeparatedSyntaxList args, + SemanticModel semanticModel, + CancellationToken ct) + { + var viewTypeFullName = InvalidOperationExceptionHelper.EnsureNotNull( + ExtractorValidation.GetTypeDisplayName(semanticModel.GetTypeInfo(memberAccess.Expression, ct).Type), + "view type display name"); + + var viewModelTypeFullName = InvalidOperationExceptionHelper.EnsureNotNull( + ExtractorValidation.GetTypeDisplayName(semanticModel.GetTypeInfo(args[0].Expression, ct).Type), + "view model type display name"); + + return (viewTypeFullName, viewModelTypeFullName); } /// - /// Determines whether a property is a settable public instance Command property typed as ICommand. + /// Resolves the event the command binds to and what the control supports, from the explicit + /// toEvent argument when present and the control's own members otherwise. /// + /// The resolved BindCommand method. + /// The invocation arguments. + /// The property path to the bound control. + /// The control selector expression. + /// The semantic model. + /// Cancellation token. + /// The event name, its argument type, and the control's binding capabilities. + private static (string? EventName, string? EventArgsTypeFullName, ControlCapabilities Capabilities) ResolveControlBinding( + IMethodSymbol methodSymbol, + SeparatedSyntaxList args, + PropertyPathSegment[] controlPropertyPath, + ExpressionSyntax controlPropertyArg, + SemanticModel semanticModel, + CancellationToken ct) + { + var resolvedEventName = ResolveExplicitEventName(methodSymbol, args, semanticModel, ct); + + var controlLeafType = SymbolHelpers.ResolveNamedType( + controlPropertyPath[^1], + semanticModel, + controlPropertyArg, + ct); + + var resolvedEventArgsTypeFullName = ResolveEventArgsTypeFullName(controlLeafType, ref resolvedEventName); + + return (resolvedEventName, resolvedEventArgsTypeFullName, DetectControlCapabilities(controlLeafType)); + } + + /// Determines whether a property is a settable public instance Command property typed as ICommand. /// The property to inspect. /// if the property is a settable ICommand-typed Command property. private static bool IsSettableICommandProperty(IPropertySymbol property) @@ -294,9 +298,7 @@ private static bool IsSettableICommandProperty(IPropertySymbol property) return typeName.EndsWith("ICommand", StringComparison.Ordinal); } - /// - /// Determines whether a property is a settable public instance CommandParameter property. - /// + /// Determines whether a property is a settable public instance CommandParameter property. /// The property to inspect. /// if the property is a settable CommandParameter property. private static bool IsSettableCommandParameterProperty(IPropertySymbol property) => @@ -335,9 +337,9 @@ private static ParameterOverloadInfo DetectParameterOverload( // Find the withParameter argument var paramResult = FindParameterLambda(args, semanticModel, ct); - if (paramResult != null) + if (paramResult is not null) { - result.ParameterPropertyPath = paramResult.Value.PropertyPath; + result.ParameterPropertyPath = new EquatableArray(paramResult.Value.PropertyPath); result.ParameterTypeFullName = paramResult.Value.TypeFullName; result.ParameterExpressionText = paramResult.Value.ExpressionText; @@ -345,7 +347,7 @@ private static ParameterOverloadInfo DetectParameterOverload( // expression is annotated nullable; without this the lambda over a nullable property raises CS8603. var paramPath = paramResult.Value.PropertyPath; result.ParameterIsReferenceType = paramPath is { Length: > 0 } - && paramPath[paramPath.Length - 1].IsReferenceType; + && paramPath[^1].IsReferenceType; } } else if (param.Type is INamedTypeSymbol observableType && SymbolHelpers.IsIObservable(observableType)) @@ -360,9 +362,7 @@ private static ParameterOverloadInfo DetectParameterOverload( return result; } - /// - /// Resolves an explicit toEvent event name from the invocation arguments, if present. - /// + /// Resolves an explicit toEvent event name from the invocation arguments, if present. /// The resolved method symbol. /// The invocation argument list. /// The semantic model. @@ -387,12 +387,7 @@ private static ParameterOverloadInfo DetectParameterOverload( if (IsToEventArgument(args[a], a, i)) { var constant = semanticModel.GetConstantValue(args[a].Expression, ct); - if (constant is { HasValue: true, Value: string eventName } && !string.IsNullOrEmpty(eventName)) - { - return eventName; - } - - return null; + return constant is { HasValue: true, Value: string eventName } && !string.IsNullOrEmpty(eventName) ? eventName : null; } } @@ -414,12 +409,12 @@ private static ParameterOverloadInfo DetectParameterOverload( INamedTypeSymbol? controlLeafType, ref string? resolvedEventName) { - if (controlLeafType == null) + if (controlLeafType is null) { return null; } - if (resolvedEventName == null) + if (resolvedEventName is null) { // No explicit toEvent: resolve the control's default event and its args type. resolvedEventName = EventHelpers.FindDefaultEvent(controlLeafType, out var defaultEventArgs); @@ -430,14 +425,12 @@ private static ParameterOverloadInfo DetectParameterOverload( return EventHelpers.FindEventArgsType(controlLeafType, resolvedEventName); } - /// - /// Detects command/command-parameter/enabled property capabilities on the control leaf type. - /// + /// Detects command/command-parameter/enabled property capabilities on the control leaf type. /// The resolved control leaf type, or null. /// The detected control capabilities (all false when is null). private static ControlCapabilities DetectControlCapabilities(INamedTypeSymbol? controlLeafType) { - if (controlLeafType == null) + if (controlLeafType is null) { return default; } @@ -447,9 +440,7 @@ private static ControlCapabilities DetectControlCapabilities(INamedTypeSymbol? c return new(hasCommandProperty, hasCommandParameterProperty, hasEnabledProperty); } - /// - /// Command-related property capabilities detected on a control type. - /// + /// Command-related property capabilities detected on a control type. /// Whether the control exposes a settable ICommand property. /// Whether the control exposes a settable command-parameter property. /// Whether the control exposes a settable enabled property. @@ -458,39 +449,25 @@ private readonly record struct ControlCapabilities( bool HasCommandParameter, bool HasEnabled); - /// - /// Holds the detected withParameter overload information for a BindCommand invocation. - /// + /// Holds the detected withParameter overload information for a BindCommand invocation. private sealed class ParameterOverloadInfo { - /// - /// Gets or sets a value indicating whether the overload has an IObservable withParameter. - /// + /// Gets or sets a value indicating whether the overload has an IObservable withParameter. public bool HasObservableParameter { get; set; } - /// - /// Gets or sets a value indicating whether the overload has an Expression withParameter. - /// + /// Gets or sets a value indicating whether the overload has an Expression withParameter. public bool HasExpressionParameter { get; set; } - /// - /// Gets or sets the fully qualified parameter type name, or null. - /// + /// Gets or sets the fully qualified parameter type name, or null. public string? ParameterTypeFullName { get; set; } - /// - /// Gets or sets a value indicating whether the detected parameter type is a reference type. - /// + /// Gets or sets a value indicating whether the detected parameter type is a reference type. public bool ParameterIsReferenceType { get; set; } - /// - /// Gets or sets the parameter property path, or null. - /// - public PropertyPathSegment[]? ParameterPropertyPath { get; set; } + /// Gets or sets the parameter property path, or null. + public EquatableArray? ParameterPropertyPath { get; set; } - /// - /// Gets or sets the normalized parameter expression text, or null. - /// + /// Gets or sets the normalized parameter expression text, or null. public string? ParameterExpressionText { get; set; } } } diff --git a/src/ReactiveUI.Binding.SourceGenerators/Helpers/EventHelpers.cs b/src/ReactiveUI.Binding.SourceGenerators/Helpers/EventHelpers.cs index 0af68cc..d2be35a 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Helpers/EventHelpers.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Helpers/EventHelpers.cs @@ -6,15 +6,10 @@ namespace ReactiveUI.Binding.SourceGenerators.Helpers; -/// -/// Provides event detection helpers for command binding. -/// +/// Provides event detection helpers for command binding. internal static class EventHelpers { - /// - /// Finds the default event on a control type for command binding. - /// Searches for Click, TouchUpInside, Pressed in order. - /// + /// Finds the default event on a control type for command binding. Searches for Click, TouchUpInside, Pressed in order. /// The control type. /// The resulting event args type name. /// The name of the default event, or null if not found. @@ -26,7 +21,7 @@ internal static class EventHelpers for (var i = 0; i < defaultEvents.Length; i++) { var argsType = FindEventArgsType(controlType, defaultEvents[i]); - if (argsType != null) + if (argsType is not null) { eventArgsType = argsType; return defaultEvents[i]; @@ -36,16 +31,14 @@ internal static class EventHelpers return null; } - /// - /// Finds the EventArgs type for a named event on a type, searching the type hierarchy. - /// + /// Finds the EventArgs type for a named event on a type, searching the type hierarchy. /// The type symbol. /// The name of the event. /// The name of the EventArgs type, or null if the event was not found. internal static string? FindEventArgsType(INamedTypeSymbol type, string eventName) { var current = type; - while (current != null) + while (current is not null) { var members = current.GetMembers(eventName); for (var i = 0; i < members.Length; i++) diff --git a/src/ReactiveUI.Binding.SourceGenerators/Helpers/ExtractorValidation.cs b/src/ReactiveUI.Binding.SourceGenerators/Helpers/ExtractorValidation.cs index be85d23..2918bc6 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Helpers/ExtractorValidation.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Helpers/ExtractorValidation.cs @@ -14,9 +14,7 @@ namespace ReactiveUI.Binding.SourceGenerators.Helpers; /// internal static class ExtractorValidation { - /// - /// The number of parameters on a standard .NET event handler delegate (sender, event args). - /// + /// The number of parameters on a standard .NET event handler delegate (sender, event args). private const int StandardEventHandlerParameterCount = 2; /// @@ -31,9 +29,7 @@ containingTypeName is Constants.StubExtensionClassName or Constants.SchedulerExtensionClassName or Constants.GeneratedExtensionClassName; - /// - /// Checks whether an invocation has at least the required number of arguments. - /// + /// Checks whether an invocation has at least the required number of arguments. /// The actual argument count. /// The minimum required argument count. /// if there are enough arguments; otherwise . @@ -52,20 +48,14 @@ internal static bool HasMinimumArguments(int argumentCount, int minimumRequired) internal static bool HasItems(ImmutableArray items) => !items.IsDefaultOrEmpty; - /// - /// Extracts an from a , - /// returning null if the resolved symbol is not a method. - /// + /// Extracts an from a , returning null if the resolved symbol is not a method. /// The symbol info from GetSymbolInfo. /// The method symbol, or null. [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static IMethodSymbol? ExtractMethodSymbol(SymbolInfo symbolInfo) => symbolInfo.Symbol as IMethodSymbol; - /// - /// Gets the fully qualified display name of a type symbol, - /// returning null if the symbol is null. - /// + /// Gets the fully qualified display name of a type symbol, returning null if the symbol is null. /// The type symbol, which may be null. /// The fully qualified type name, or null. [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -117,11 +107,8 @@ internal static string ResolveEventArgsType(ITypeSymbol? delegateType) } var invokeMethod = namedDelegateType.DelegateInvokeMethod; - if (invokeMethod is { Parameters.Length: StandardEventHandlerParameterCount }) - { - return invokeMethod.Parameters[1].Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); - } - - return "global::System.EventArgs"; + return invokeMethod is { Parameters.Length: StandardEventHandlerParameterCount } + ? invokeMethod.Parameters[1].Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) + : "global::System.EventArgs"; } } diff --git a/src/ReactiveUI.Binding.SourceGenerators/Helpers/InteractionExtractor.cs b/src/ReactiveUI.Binding.SourceGenerators/Helpers/InteractionExtractor.cs index d6e3352..b0675e1 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Helpers/InteractionExtractor.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Helpers/InteractionExtractor.cs @@ -8,20 +8,13 @@ namespace ReactiveUI.Binding.SourceGenerators.Helpers; -/// -/// Extracts BindInteractionInvocationInfo from BindInteraction invocations. -/// +/// Extracts BindInteractionInvocationInfo from BindInteraction invocations. internal static class InteractionExtractor { - /// - /// The minimum number of arguments a BindInteraction invocation must have - /// (view model, property name, handler). - /// + /// The minimum number of arguments a BindInteraction invocation must have (view model, property name, handler). private const int MinimumBindInteractionArgumentCount = 3; - /// - /// Pipeline B transform: extracts BindInteractionInvocationInfo from a BindInteraction invocation. - /// + /// Pipeline B transform: extracts BindInteractionInvocationInfo from a BindInteraction invocation. /// The generator syntax context. /// Cancellation token. /// A BindInteractionInvocationInfo POCO, or null if the invocation is not analyzable. @@ -35,7 +28,7 @@ internal static class InteractionExtractor var semanticModel = context.SemanticModel; var methodSymbol = ExtractorValidation.ExtractMethodSymbol(semanticModel.GetSymbolInfo(invocation, ct)); - if (methodSymbol == null) + if (methodSymbol is null) { return null; } @@ -52,7 +45,7 @@ internal static class InteractionExtractor // Extract the interaction property path from the second argument (propertyName) var propertyNameArg = args[1].Expression; var interactionPropertyPath = SyntaxHelpers.ExtractPropertyPathFromLambda(propertyNameArg, semanticModel, ct); - if (interactionPropertyPath == null) + if (interactionPropertyPath is null) { return null; } @@ -128,7 +121,7 @@ private static void ResolveInteractionTypeArguments( } var body = SyntaxHelpers.GetLambdaBody(lambda); - if (body == null) + if (body is null) { return; } diff --git a/src/ReactiveUI.Binding.SourceGenerators/Helpers/InvalidOperationExceptionHelper.cs b/src/ReactiveUI.Binding.SourceGenerators/Helpers/InvalidOperationExceptionHelper.cs index 840b0bc..b4c4cd3 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Helpers/InvalidOperationExceptionHelper.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Helpers/InvalidOperationExceptionHelper.cs @@ -28,9 +28,7 @@ internal static T EnsureNotNull(T? value, string context) where T : class => value ?? throw new InvalidOperationException($"Unexpected null in source generator pipeline: {context}"); - /// - /// Returns the value if non-null and non-empty; otherwise throws . - /// + /// Returns the value if non-null and non-empty; otherwise throws . /// The string value to check. /// A description of what was unexpectedly null or empty. /// The non-null, non-empty . diff --git a/src/ReactiveUI.Binding.SourceGenerators/Helpers/ObservationExtractor.cs b/src/ReactiveUI.Binding.SourceGenerators/Helpers/ObservationExtractor.cs index 00a42d4..859bd91 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Helpers/ObservationExtractor.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Helpers/ObservationExtractor.cs @@ -8,50 +8,38 @@ namespace ReactiveUI.Binding.SourceGenerators.Helpers; -/// -/// Extracts InvocationInfo from WhenChanged, WhenChanging, WhenAnyValue, and WhenAny invocations. -/// +/// Extracts InvocationInfo from WhenChanged, WhenChanging, WhenAnyValue, and WhenAny invocations. internal static class ObservationExtractor { - /// - /// Pipeline B transform: extracts InvocationInfo from a WhenChanged invocation. - /// + /// Pipeline B transform: extracts InvocationInfo from a WhenChanged invocation. /// The generator syntax context. /// Cancellation token. /// An InvocationInfo POCO, or null if the invocation is not analyzable. - internal static InvocationInfo? ExtractWhenChangedInvocation(GeneratorSyntaxContext context, CancellationToken ct) - => ExtractInvocationInfo(context, false, Constants.WhenChangedMethodName, ct); + internal static InvocationInfo? ExtractWhenChangedInvocation(GeneratorSyntaxContext context, CancellationToken ct) => + ExtractInvocationInfo(context, false, Constants.WhenChangedMethodName, ct); - /// - /// Pipeline B transform: extracts InvocationInfo from a WhenChanging invocation. - /// + /// Pipeline B transform: extracts InvocationInfo from a WhenChanging invocation. /// The generator syntax context. /// Cancellation token. /// An InvocationInfo POCO, or null if the invocation is not analyzable. - internal static InvocationInfo? ExtractWhenChangingInvocation(GeneratorSyntaxContext context, CancellationToken ct) - => ExtractInvocationInfo(context, true, Constants.WhenChangingMethodName, ct); + internal static InvocationInfo? ExtractWhenChangingInvocation(GeneratorSyntaxContext context, CancellationToken ct) => + ExtractInvocationInfo(context, true, Constants.WhenChangingMethodName, ct); - /// - /// Pipeline B transform: extracts InvocationInfo from a WhenAnyValue invocation. - /// + /// Pipeline B transform: extracts InvocationInfo from a WhenAnyValue invocation. /// The generator syntax context. /// Cancellation token. /// An InvocationInfo POCO, or null if the invocation is not analyzable. - internal static InvocationInfo? ExtractWhenAnyValueInvocation(GeneratorSyntaxContext context, CancellationToken ct) - => ExtractInvocationInfo(context, false, Constants.WhenAnyValueMethodName, ct); + internal static InvocationInfo? ExtractWhenAnyValueInvocation(GeneratorSyntaxContext context, CancellationToken ct) => + ExtractInvocationInfo(context, false, Constants.WhenAnyValueMethodName, ct); - /// - /// Pipeline B transform: extracts InvocationInfo from a WhenAny invocation (with IObservedChange selector). - /// + /// Pipeline B transform: extracts InvocationInfo from a WhenAny invocation (with IObservedChange selector). /// The generator syntax context. /// Cancellation token. /// An InvocationInfo POCO, or null if the invocation is not analyzable. - internal static InvocationInfo? ExtractWhenAnyInvocation(GeneratorSyntaxContext context, CancellationToken ct) - => ExtractInvocationInfo(context, false, Constants.WhenAnyMethodName, ct); + internal static InvocationInfo? ExtractWhenAnyInvocation(GeneratorSyntaxContext context, CancellationToken ct) => + ExtractInvocationInfo(context, false, Constants.WhenAnyMethodName, ct); - /// - /// Extracts the invocation info from the generator syntax context. - /// + /// Extracts the invocation info from the generator syntax context. /// The generator syntax context. /// A value indicating whether the invocation is before a change. /// The expected method name. @@ -69,7 +57,7 @@ internal static class ObservationExtractor var semanticModel = context.SemanticModel; var methodSymbol = ExtractorValidation.ExtractMethodSymbol(semanticModel.GetSymbolInfo(invocation, ct)); - if (methodSymbol == null) + if (methodSymbol is null) { return null; } @@ -148,7 +136,7 @@ private static bool CollectPropertyPaths( if (parameter.Type is INamedTypeSymbol { Name: "Expression" }) { var path = SyntaxHelpers.ExtractPropertyPathFromLambda(args[i].Expression, semanticModel, ct); - if (path != null) + if (path is not null) { propertyPaths.Add(new(path)); expressionTexts.Add( @@ -202,14 +190,14 @@ private static string ComputeReturnTypeFullName( { var path = propertyPaths[i]; var leafType = path[path.Length - 1].PropertyTypeFullName; - tupleBuilder.Append(leafType).Append(" property").Append(i + 1); + _ = tupleBuilder.Append(leafType).Append(" property").Append(i + 1); if (i < propertyPaths.Count - 1) { - tupleBuilder.Append(", "); + _ = tupleBuilder.Append(", "); } } - tupleBuilder.Append(')'); + _ = tupleBuilder.Append(')'); return tupleBuilder.ToString(); } } diff --git a/src/ReactiveUI.Binding.SourceGenerators/Helpers/SymbolHelpers.cs b/src/ReactiveUI.Binding.SourceGenerators/Helpers/SymbolHelpers.cs index e05532d..8cbd7d1 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Helpers/SymbolHelpers.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Helpers/SymbolHelpers.cs @@ -2,30 +2,21 @@ // ReactiveUI Association Incorporated licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using Microsoft.CodeAnalysis; namespace ReactiveUI.Binding.SourceGenerators.Helpers; -/// -/// Provides well-known symbol caching and type-checking helpers shared across all extractors. -/// +/// Provides well-known symbol caching and type-checking helpers shared across all extractors. internal static class SymbolHelpers { - /// - /// The number of type arguments on IInteraction<TInput, TOutput>. - /// + /// The number of type arguments on IInteraction<TInput, TOutput>. private const int InteractionTypeArgumentCount = 2; - /// - /// The symbol cache for the compilation. - /// + /// The symbol cache for the compilation. private static readonly ConditionalWeakTable SymbolCache = new(); - /// - /// Gets the well-known symbols for a compilation. - /// + /// Gets the well-known symbols for a compilation. /// The compilation. /// The well-known symbols box. internal static WellKnownSymbolsBox GetWellKnownSymbols(Compilation compilation) => @@ -64,7 +55,7 @@ internal static string ExtractInnerObservableType( if (argExpression is Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax lambda) { var body = SyntaxHelpers.GetLambdaBody(lambda); - if (body != null) + if (body is not null) { body = SyntaxHelpers.UnwrapNullForgiving(body); if (body is Microsoft.CodeAnalysis.CSharp.Syntax.MemberAccessExpressionSyntax memberAccess) @@ -73,7 +64,7 @@ internal static string ExtractInnerObservableType( if (memberSymbol is IPropertySymbol { Type: INamedTypeSymbol namedType }) { var observableType = TryGetObservableTypeArgument(namedType); - if (observableType != null) + if (observableType is not null) { return observableType; } @@ -86,20 +77,16 @@ internal static string ExtractInnerObservableType( return leafSegment.PropertyTypeFullName; } - /// - /// Checks if a named type symbol is IObservable<T>. - /// + /// Checks if a named type symbol is IObservable<T>. /// The type symbol to check. /// A value indicating whether the type is IObservable<T>. [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool IsIObservable(INamedTypeSymbol type) => type is { IsGenericType: true, TypeArguments.Length: 1 } - && type.ConstructedFrom.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) == - "global::System.IObservable"; + && type.ConstructedFrom.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) + == "global::System.IObservable"; - /// - /// Checks if a type is IInteraction<TInput, TOutput>. - /// + /// Checks if a type is IInteraction<TInput, TOutput>. /// The type symbol to check. /// A value indicating whether the type is IInteraction<TInput, TOutput>. [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -107,9 +94,7 @@ internal static bool IsInteractionType(INamedTypeSymbol type) => type is { IsGenericType: true, TypeArguments.Length: InteractionTypeArgumentCount, MetadataName: "IInteraction`2" } && type.ContainingNamespace!.ToDisplayString() == "ReactiveUI.Binding"; - /// - /// Extracts TInput and TOutput type arguments from a type that implements IInteraction<TInput, TOutput>. - /// + /// Extracts TInput and TOutput type arguments from a type that implements IInteraction<TInput, TOutput>. /// The type symbol. /// The resulting TInput type name. /// The resulting TOutput type name. @@ -158,14 +143,12 @@ internal static bool ExtractInteractionTypeArguments(ITypeSymbol type, out strin /// [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool DetectHasConverterOverride(IParameterSymbol parameter) => - parameter.Name is "converter" or "sourceToTargetConverter" or "vmToViewConverter" + parameter.Name is "converter" or "sourceToTargetConverter" or "vmToViewConverter" or "viewModelToViewConverter" && parameter.Type is INamedTypeSymbol paramType && paramType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) .EndsWith("IBindingTypeConverter", StringComparison.Ordinal); - /// - /// Resolves a PropertyPathSegment leaf type to its INamedTypeSymbol using the semantic model. - /// + /// Resolves a PropertyPathSegment leaf type to its INamedTypeSymbol using the semantic model. /// The property path segment. /// The semantic model. /// The lambda expression. @@ -184,7 +167,7 @@ parameter.Name is "converter" or "sourceToTargetConverter" or "vmToViewConverter var body = SyntaxHelpers.GetLambdaBody(lambda); - if (body == null) + if (body is null) { return null; } @@ -196,12 +179,7 @@ parameter.Name is "converter" or "sourceToTargetConverter" or "vmToViewConverter } var memberSymbol = semanticModel.GetSymbolInfo(memberAccess, ct).Symbol; - if (!(memberSymbol is IPropertySymbol { Type: INamedTypeSymbol namedType })) - { - return null; - } - - return namedType; + return !(memberSymbol is IPropertySymbol { Type: INamedTypeSymbol namedType }) ? null : namedType; } /// @@ -237,52 +215,28 @@ parameter.Name is "converter" or "sourceToTargetConverter" or "vmToViewConverter /// internal sealed class WellKnownSymbolsBox { - /// - /// Gets or sets the INPC symbol. - /// - [SuppressMessage( - "Minor Code Smell", - "S100:Methods and properties should be named in PascalCase", - Justification = "INPC abbreviates INotifyPropertyChanged, an established acronym matching the ReactiveUI domain terminology.")] + /// Gets or sets the INPC symbol. internal INamedTypeSymbol? INPC { get; set; } - /// - /// Gets or sets the INPChanging symbol. - /// - [SuppressMessage( - "Minor Code Smell", - "S100:Methods and properties should be named in PascalCase", - Justification = "INPChanging abbreviates INotifyPropertyChanging, an established acronym matching the ReactiveUI domain terminology.")] + /// Gets or sets the INPChanging symbol. internal INamedTypeSymbol? INPChanging { get; set; } - /// - /// Gets or sets the IReactiveObject symbol. - /// + /// Gets or sets the IReactiveObject symbol. internal INamedTypeSymbol? IReactiveObject { get; set; } - /// - /// Gets or sets the WpfDependencyObject symbol. - /// + /// Gets or sets the WpfDependencyObject symbol. internal INamedTypeSymbol? WpfDependencyObject { get; set; } - /// - /// Gets or sets the WinUIDependencyObject symbol. - /// + /// Gets or sets the WinUIDependencyObject symbol. internal INamedTypeSymbol? WinUIDependencyObject { get; set; } - /// - /// Gets or sets the NSObject symbol. - /// + /// Gets or sets the NSObject symbol. internal INamedTypeSymbol? NSObject { get; set; } - /// - /// Gets or sets the WinFormsComponent symbol. - /// + /// Gets or sets the WinFormsComponent symbol. internal INamedTypeSymbol? WinFormsComponent { get; set; } - /// - /// Gets or sets the AndroidView symbol. - /// + /// Gets or sets the AndroidView symbol. internal INamedTypeSymbol? AndroidView { get; set; } } } diff --git a/src/ReactiveUI.Binding.SourceGenerators/Helpers/SyntaxHelpers.cs b/src/ReactiveUI.Binding.SourceGenerators/Helpers/SyntaxHelpers.cs index 233c168..df0f023 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Helpers/SyntaxHelpers.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Helpers/SyntaxHelpers.cs @@ -10,14 +10,10 @@ namespace ReactiveUI.Binding.SourceGenerators.Helpers; -/// -/// Provides syntax-level helpers for extracting property paths from lambda expressions. -/// +/// Provides syntax-level helpers for extracting property paths from lambda expressions. internal static class SyntaxHelpers { - /// - /// Extracts the property path from a lambda expression. - /// + /// Extracts the property path from a lambda expression. /// The expression syntax. /// The semantic model. /// Cancellation token. @@ -37,14 +33,16 @@ internal static class SyntaxHelpers // Get the lambda body (only SimpleLambda and ParenthesizedLambda exist in Roslyn) var body = GetLambdaBody(lambda); - if (body == null) + if (body is null) { return null; } // Decompose member access chain: x.A.B.C → [A, B, C] // Also handles null-forgiving operator: x.A!.B!.C → [A, B, C] - var segments = new List(4); + const int TypicalPathDepth = 4; + + var segments = new List(TypicalPathDepth); var current = UnwrapNullForgiving(body); while (current is MemberAccessExpressionSyntax memberAccess) @@ -83,11 +81,8 @@ internal static class SyntaxHelpers return [.. segments]; } - /// - /// Extracts the body expression from a . - /// Handles both and - /// . - /// + /// Extracts the body expression from a . + /// Handles both and . /// The lambda expression. /// The body as an , or null if the body is a block or unsupported form. [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ReactiveUI.Binding.SourceGenerators/Helpers/TypeDetectionExtractor.cs b/src/ReactiveUI.Binding.SourceGenerators/Helpers/TypeDetectionExtractor.cs index cdb579b..1eef1ad 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Helpers/TypeDetectionExtractor.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Helpers/TypeDetectionExtractor.cs @@ -8,9 +8,7 @@ namespace ReactiveUI.Binding.SourceGenerators.Helpers; -/// -/// Pipeline A transform: extracts ClassBindingInfo from class declarations. -/// +/// Pipeline A transform: extracts ClassBindingInfo from class declarations. internal static class TypeDetectionExtractor { /// @@ -59,9 +57,7 @@ internal static class TypeDetectionExtractor properties); } - /// - /// Extracts the properties from a named type symbol. - /// + /// Extracts the properties from a named type symbol. /// The type symbol. /// Cancellation token. /// An array of observable property info. @@ -70,7 +66,9 @@ internal static EquatableArray ExtractProperties( INamedTypeSymbol typeSymbol, CancellationToken ct) { - var properties = new List(16); + const int TypicalObservablePropertyCount = 16; + + var properties = new List(TypicalObservablePropertyCount); var members = typeSymbol.GetMembers(); for (var i = 0; i < members.Length; i++) @@ -94,7 +92,7 @@ internal static EquatableArray ExtractProperties( for (var j = 0; j < members.Length; j++) { if (members[j] is IFieldSymbol { IsStatic: true } field - && field.Name == property.Name + "Property") + && field.Name == $"{property.Name}Property") { isDependencyProperty = true; break; @@ -112,9 +110,7 @@ internal static EquatableArray ExtractProperties( return new([.. properties]); } - /// - /// Walks AllInterfaces to detect notification interfaces. - /// + /// Walks AllInterfaces to detect notification interfaces. /// The type to inspect. /// The cached well-known symbols. /// Cancellation token. @@ -139,27 +135,25 @@ private static void DetectImplementedInterfaces( ct.ThrowIfCancellationRequested(); var iface = allInterfaces[i]; - if (wellKnown.IReactiveObject != null && - SymbolEqualityComparer.Default.Equals(iface, wellKnown.IReactiveObject)) + if (wellKnown.IReactiveObject is not null + && SymbolEqualityComparer.Default.Equals(iface, wellKnown.IReactiveObject)) { implementsIReactiveObject = true; } - if (wellKnown.INPC != null && SymbolEqualityComparer.Default.Equals(iface, wellKnown.INPC)) + if (wellKnown.INPC is not null && SymbolEqualityComparer.Default.Equals(iface, wellKnown.INPC)) { implementsINPC = true; } - if (wellKnown.INPChanging != null && SymbolEqualityComparer.Default.Equals(iface, wellKnown.INPChanging)) + if (wellKnown.INPChanging is not null && SymbolEqualityComparer.Default.Equals(iface, wellKnown.INPChanging)) { implementsINPChanging = true; } } } - /// - /// Walks the base type chain to detect platform-specific base types (WPF/WinUI/KVO/WinForms/Android). - /// + /// Walks the base type chain to detect platform-specific base types (WPF/WinUI/KVO/WinForms/Android). /// The type to inspect. /// The cached well-known symbols. /// Cancellation token. @@ -176,7 +170,7 @@ private static PlatformBaseTypeFlags DetectPlatformBaseTypes( var android = false; var baseType = typeSymbol.BaseType; - while (baseType != null) + while (baseType is not null) { ct.ThrowIfCancellationRequested(); @@ -192,18 +186,14 @@ private static PlatformBaseTypeFlags DetectPlatformBaseTypes( return new(wpf, winui, ns, winforms, android); } - /// - /// Determines whether equals the (possibly null) candidate symbol. - /// + /// Determines whether equals the (possibly null) candidate symbol. /// The symbol to compare. /// The candidate symbol; null is treated as no match. /// true if the candidate is non-null and equal; otherwise, false. private static bool Matches(INamedTypeSymbol symbol, INamedTypeSymbol? candidate) => - candidate != null && SymbolEqualityComparer.Default.Equals(symbol, candidate); + candidate is not null && SymbolEqualityComparer.Default.Equals(symbol, candidate); - /// - /// Platform-specific base-type detection flags for a class. - /// + /// Platform-specific base-type detection flags for a class. /// Whether the type inherits a WPF DependencyObject. /// Whether the type inherits a WinUI DependencyObject. /// Whether the type inherits an Apple NSObject. diff --git a/src/ReactiveUI.Binding.SourceGenerators/Helpers/ViewRegistrationExtractor.cs b/src/ReactiveUI.Binding.SourceGenerators/Helpers/ViewRegistrationExtractor.cs index 04601b8..6adebfa 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Helpers/ViewRegistrationExtractor.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Helpers/ViewRegistrationExtractor.cs @@ -8,14 +8,10 @@ namespace ReactiveUI.Binding.SourceGenerators.Helpers; -/// -/// Extracts from class declarations implementing IViewFor<T>. -/// +/// Extracts from class declarations implementing IViewFor<T>. internal static class ViewRegistrationExtractor { - /// - /// Extracts a from a class that implements IViewFor<T>. - /// + /// Extracts a from a class that implements IViewFor<T>. /// The generator syntax context. /// Cancellation token. /// A if the class implements IViewFor<T>; otherwise, . @@ -31,7 +27,7 @@ internal static class ViewRegistrationExtractor return null; } - var iViewForGeneric = semanticModel.Compilation.GetTypeByMetadataName( + var viewForGenericInterface = semanticModel.Compilation.GetTypeByMetadataName( Constants.IViewForGenericMetadataName); // Walk AllInterfaces to find IViewFor @@ -41,9 +37,9 @@ internal static class ViewRegistrationExtractor ct.ThrowIfCancellationRequested(); var iface = allInterfaces[i]; - if (iViewForGeneric is object + if (viewForGenericInterface is not null && iface.IsGenericType - && SymbolEqualityComparer.Default.Equals(iface.OriginalDefinition, iViewForGeneric) + && SymbolEqualityComparer.Default.Equals(iface.OriginalDefinition, viewForGenericInterface) && iface.TypeArguments.Length == 1) { // Check [ExcludeFromViewRegistration] only after confirming IViewFor is @@ -74,9 +70,7 @@ internal static class ViewRegistrationExtractor return null; } - /// - /// Checks whether the type has the specified attribute applied. - /// + /// Checks whether the type has the specified attribute applied. /// The type to check. /// The metadata name of the attribute. /// The compilation for symbol resolution. @@ -100,9 +94,7 @@ private static bool HasAttribute(INamedTypeSymbol type, string attributeMetadata return false; } - /// - /// Extracts the contract string from [ViewContract("...")] if present. - /// + /// Extracts the contract string from [ViewContract("...")] if present. /// The type to check. /// The compilation for symbol resolution. /// The contract string, or if not present. @@ -128,9 +120,7 @@ private static bool HasAttribute(INamedTypeSymbol type, string attributeMetadata return null; } - /// - /// Checks whether the type has an accessible parameterless constructor (public or internal). - /// + /// Checks whether the type has an accessible parameterless constructor (public or internal). /// The type to check. /// if a parameterless constructor is accessible; otherwise, . private static bool HasAccessibleParameterlessConstructor(INamedTypeSymbol type) @@ -139,7 +129,7 @@ private static bool HasAccessibleParameterlessConstructor(INamedTypeSymbol type) for (var i = 0; i < constructors.Length; i++) { var ctor = constructors[i]; - if (ctor.Parameters.Length == 0 + if (ctor.Parameters.IsEmpty && (ctor.DeclaredAccessibility == Accessibility.Public || ctor.DeclaredAccessibility == Accessibility.Internal)) { diff --git a/src/ReactiveUI.Binding.SourceGenerators/Helpers/WhenAnyObservableExtractor.cs b/src/ReactiveUI.Binding.SourceGenerators/Helpers/WhenAnyObservableExtractor.cs index 4e05085..d675c93 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Helpers/WhenAnyObservableExtractor.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Helpers/WhenAnyObservableExtractor.cs @@ -8,9 +8,7 @@ namespace ReactiveUI.Binding.SourceGenerators.Helpers; -/// -/// Extracts WhenAnyObservableInvocationInfo from WhenAnyObservable invocations. -/// +/// Extracts WhenAnyObservableInvocationInfo from WhenAnyObservable invocations. internal static class WhenAnyObservableExtractor { /// @@ -22,7 +20,7 @@ internal static class WhenAnyObservableExtractor /// Cancellation token. /// A WhenAnyObservableInvocationInfo POCO, or null if the invocation is not analyzable. /// If the cancellation token is triggered. - internal static WhenAnyObservableInvocationInfo? ExtractWhenAnyObservableInvocation( + internal static WhenAnyObservableInvocationInfo? ExtractWhenAnyObservableInvocation( GeneratorSyntaxContext context, CancellationToken ct) { @@ -31,7 +29,7 @@ internal static class WhenAnyObservableExtractor var semanticModel = context.SemanticModel; var methodSymbol = ExtractorValidation.ExtractMethodSymbol(semanticModel.GetSymbolInfo(invocation, ct)); - if (methodSymbol == null) + if (methodSymbol is null) { return null; } @@ -43,38 +41,8 @@ internal static class WhenAnyObservableExtractor } var args = invocation.ArgumentList.Arguments; - var propertyPaths = new List>(args.Count); - var expressionTexts = new List(args.Count); - var innerObservableTypes = new List(args.Count); - var hasSelector = false; - - // Loop over parameters to identify expression parameters and selector - for (var i = 0; i < methodSymbol.Parameters.Length; i++) - { - var parameter = methodSymbol.Parameters[i]; - - // Check if parameter type is Expression?>> - if (parameter.Type is INamedTypeSymbol { Name: "Expression" }) - { - var path = SyntaxHelpers.ExtractPropertyPathFromLambda(args[i].Expression, semanticModel, ct); - if (path != null) - { - propertyPaths.Add(new(path)); - expressionTexts.Add( - CodeGeneration.CodeGeneratorHelpers.NormalizeLambdaText(args[i].Expression.ToString())); - - // Extract the inner type T from the leaf property type IObservable? - var leafSegment = path[path.Length - 1]; - var innerType = - SymbolHelpers.ExtractInnerObservableType(leafSegment, semanticModel, args[i].Expression, ct); - innerObservableTypes.Add(innerType); - } - } - else if (parameter.Name == "selector") - { - hasSelector = true; - } - } + var (propertyPaths, expressionTexts, innerObservableTypes, hasSelector) = + CollectObservableArguments(methodSymbol, args, semanticModel, ct); if (propertyPaths.Count == 0) { @@ -108,4 +76,58 @@ internal static class WhenAnyObservableExtractor hasSelector, new([.. expressionTexts])); } + + /// + /// Walks the invocation's parameters, collecting one property path, expression text and inner + /// observable type per Expression<Func<TSender, IObservable<T>>> argument. + /// + /// The resolved method. + /// The invocation arguments. + /// The semantic model. + /// Cancellation token. + /// The observed paths, their expression texts, their inner types, and whether a selector was supplied. + private static (List> PropertyPaths, List ExpressionTexts, List InnerObservableTypes, bool HasSelector) + CollectObservableArguments( + IMethodSymbol methodSymbol, + SeparatedSyntaxList args, + SemanticModel semanticModel, + CancellationToken ct) + { + var propertyPaths = new List>(args.Count); + var expressionTexts = new List(args.Count); + var innerObservableTypes = new List(args.Count); + var hasSelector = false; + + for (var i = 0; i < methodSymbol.Parameters.Length; i++) + { + var parameter = methodSymbol.Parameters[i]; + + if (parameter.Name == "selector") + { + hasSelector = true; + continue; + } + + if (parameter.Type is not INamedTypeSymbol { Name: "Expression" }) + { + continue; + } + + var path = SyntaxHelpers.ExtractPropertyPathFromLambda(args[i].Expression, semanticModel, ct); + if (path is null) + { + continue; + } + + propertyPaths.Add(new(path)); + expressionTexts.Add( + CodeGeneration.CodeGeneratorHelpers.NormalizeLambdaText(args[i].Expression.ToString())); + + // The leaf property type is IObservable; the generated code needs T. + innerObservableTypes.Add( + SymbolHelpers.ExtractInnerObservableType(path[^1], semanticModel, args[i].Expression, ct)); + } + + return (propertyPaths, expressionTexts, innerObservableTypes, hasSelector); + } } diff --git a/src/ReactiveUI.Binding.SourceGenerators/Invocations/BindCommandInvocationGenerator.cs b/src/ReactiveUI.Binding.SourceGenerators/Invocations/BindCommandInvocationGenerator.cs index 48563b0..7d4eee8 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Invocations/BindCommandInvocationGenerator.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Invocations/BindCommandInvocationGenerator.cs @@ -9,19 +9,15 @@ namespace ReactiveUI.Binding.SourceGenerators.Invocations; -/// -/// Detects BindCommand invocations and generates per-invocation command binding code. -/// +/// Detects BindCommand invocations and generates per-invocation command binding code. internal static class BindCommandInvocationGenerator { - /// - /// Registers the BindCommand invocation detection pipeline. - /// + /// Registers the BindCommand invocation detection pipeline. /// The generator initialization context. /// The shared type detection pipeline. /// The consumer compilation's C# language-feature snapshot. internal static void Register( - IncrementalGeneratorInitializationContext context, + in IncrementalGeneratorInitializationContext context, IncrementalValuesProvider allClasses, IncrementalValueProvider languageFeatures) { @@ -41,7 +37,7 @@ internal static void Register( static (ctx, data) => { var source = BindCommandCodeGenerator.Generate(data.Left.Left, data.Left.Right, data.Right); - if (source == null) + if (source is null) { return; } diff --git a/src/ReactiveUI.Binding.SourceGenerators/Invocations/BindInteractionInvocationGenerator.cs b/src/ReactiveUI.Binding.SourceGenerators/Invocations/BindInteractionInvocationGenerator.cs index 3a22113..db0a2f3 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Invocations/BindInteractionInvocationGenerator.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Invocations/BindInteractionInvocationGenerator.cs @@ -9,19 +9,15 @@ namespace ReactiveUI.Binding.SourceGenerators.Invocations; -/// -/// Detects BindInteraction invocations and generates per-invocation binding code. -/// +/// Detects BindInteraction invocations and generates per-invocation binding code. internal static class BindInteractionInvocationGenerator { - /// - /// Registers the BindInteraction invocation detection pipeline. - /// + /// Registers the BindInteraction invocation detection pipeline. /// The generator initialization context. /// The shared type detection pipeline. /// The consumer compilation's C# language-feature snapshot. internal static void Register( - IncrementalGeneratorInitializationContext context, + in IncrementalGeneratorInitializationContext context, IncrementalValuesProvider allClasses, IncrementalValueProvider languageFeatures) { @@ -41,7 +37,7 @@ internal static void Register( static (ctx, data) => { var source = BindInteractionCodeGenerator.Generate(data.Left.Left, data.Left.Right, data.Right); - if (source == null) + if (source is null) { return; } diff --git a/src/ReactiveUI.Binding.SourceGenerators/Invocations/BindInvocationGenerator.cs b/src/ReactiveUI.Binding.SourceGenerators/Invocations/BindInvocationGenerator.cs index 42375f5..cdc0fc8 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Invocations/BindInvocationGenerator.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Invocations/BindInvocationGenerator.cs @@ -9,25 +9,21 @@ namespace ReactiveUI.Binding.SourceGenerators.Invocations; -/// -/// Detects Bind (view-first two-way binding) invocations and generates per-invocation binding code. -/// +/// Detects Bind (view-first two-way binding) invocations and generates per-invocation binding code. internal static class BindInvocationGenerator { - /// - /// Registers the Bind invocation detection pipeline. - /// + /// Registers the Bind invocation detection pipeline. /// The generator initialization context. /// The shared type detection pipeline. /// The consumer compilation's C# language-feature snapshot. internal static void Register( - IncrementalGeneratorInitializationContext context, + in IncrementalGeneratorInitializationContext context, IncrementalValuesProvider allClasses, IncrementalValueProvider languageFeatures) { var invocations = context.SyntaxProvider .CreateSyntaxProvider( - static (node, ct) => RoslynHelpers.IsBindSpecificInvocation(node, ct), + RoslynHelpers.IsBindSpecificInvocation, BindingExtractor.ExtractBindInvocation) .Where(static x => x is not null) .Select(static (x, _) => x!); @@ -41,7 +37,7 @@ internal static void Register( static (ctx, data) => { var source = BindCodeGenerator.Generate(data.Left.Left, data.Left.Right, data.Right); - if (source == null) + if (source is null) { return; } diff --git a/src/ReactiveUI.Binding.SourceGenerators/Invocations/BindOneWayInvocationGenerator.cs b/src/ReactiveUI.Binding.SourceGenerators/Invocations/BindOneWayInvocationGenerator.cs index de86a21..960eda2 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Invocations/BindOneWayInvocationGenerator.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Invocations/BindOneWayInvocationGenerator.cs @@ -9,25 +9,21 @@ namespace ReactiveUI.Binding.SourceGenerators.Invocations; -/// -/// Detects BindOneWay invocations and generates per-invocation binding code. -/// +/// Detects BindOneWay invocations and generates per-invocation binding code. internal static class BindOneWayInvocationGenerator { - /// - /// Registers the BindOneWay invocation detection pipeline. - /// + /// Registers the BindOneWay invocation detection pipeline. /// The generator initialization context. /// The shared type detection pipeline. /// The consumer compilation's C# language-feature snapshot. internal static void Register( - IncrementalGeneratorInitializationContext context, + in IncrementalGeneratorInitializationContext context, IncrementalValuesProvider allClasses, IncrementalValueProvider languageFeatures) { var invocations = context.SyntaxProvider .CreateSyntaxProvider( - static (node, ct) => RoslynHelpers.IsBindOneWaySpecificInvocation(node, ct), + RoslynHelpers.IsBindOneWaySpecificInvocation, BindingExtractor.ExtractBindInvocation) .Where(static x => x is not null) .Select(static (x, _) => x!); @@ -41,7 +37,7 @@ internal static void Register( static (ctx, data) => { var source = BindOneWayCodeGenerator.Generate(data.Left.Left, data.Left.Right, data.Right); - if (source == null) + if (source is null) { return; } diff --git a/src/ReactiveUI.Binding.SourceGenerators/Invocations/BindToInvocationGenerator.cs b/src/ReactiveUI.Binding.SourceGenerators/Invocations/BindToInvocationGenerator.cs index aca8d7b..5be00ce 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Invocations/BindToInvocationGenerator.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Invocations/BindToInvocationGenerator.cs @@ -9,25 +9,21 @@ namespace ReactiveUI.Binding.SourceGenerators.Invocations; -/// -/// Detects BindTo invocations and generates per-invocation binding code. -/// +/// Detects BindTo invocations and generates per-invocation binding code. internal static class BindToInvocationGenerator { - /// - /// Registers the BindTo invocation detection pipeline. - /// + /// Registers the BindTo invocation detection pipeline. /// The generator initialization context. /// The shared type detection pipeline (unused; kept for signature consistency). /// The consumer compilation's C# language-feature snapshot. internal static void Register( - IncrementalGeneratorInitializationContext context, + in IncrementalGeneratorInitializationContext context, IncrementalValuesProvider allClasses, IncrementalValueProvider languageFeatures) { var invocations = context.SyntaxProvider .CreateSyntaxProvider( - static (node, ct) => RoslynHelpers.IsBindToInvocation(node, ct), + RoslynHelpers.IsBindToInvocation, BindToExtractor.ExtractBindToInvocation) .Where(static x => x is not null) .Select(static (x, _) => x!); @@ -39,7 +35,7 @@ internal static void Register( static (ctx, data) => { var source = BindToCodeGenerator.Generate(data.Left, data.Right); - if (source == null) + if (source is null) { return; } diff --git a/src/ReactiveUI.Binding.SourceGenerators/Invocations/BindTwoWayInvocationGenerator.cs b/src/ReactiveUI.Binding.SourceGenerators/Invocations/BindTwoWayInvocationGenerator.cs index 1882226..b5ead7f 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Invocations/BindTwoWayInvocationGenerator.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Invocations/BindTwoWayInvocationGenerator.cs @@ -9,25 +9,21 @@ namespace ReactiveUI.Binding.SourceGenerators.Invocations; -/// -/// Detects BindTwoWay invocations and generates per-invocation bidirectional binding code. -/// +/// Detects BindTwoWay invocations and generates per-invocation bidirectional binding code. internal static class BindTwoWayInvocationGenerator { - /// - /// Registers the BindTwoWay invocation detection pipeline. - /// + /// Registers the BindTwoWay invocation detection pipeline. /// The generator initialization context. /// The shared type detection pipeline. /// The consumer compilation's C# language-feature snapshot. internal static void Register( - IncrementalGeneratorInitializationContext context, + in IncrementalGeneratorInitializationContext context, IncrementalValuesProvider allClasses, IncrementalValueProvider languageFeatures) { var invocations = context.SyntaxProvider .CreateSyntaxProvider( - static (node, ct) => RoslynHelpers.IsBindTwoWaySpecificInvocation(node, ct), + RoslynHelpers.IsBindTwoWaySpecificInvocation, BindingExtractor.ExtractBindInvocation) .Where(static x => x is not null) .Select(static (x, _) => x!); @@ -41,7 +37,7 @@ internal static void Register( static (ctx, data) => { var source = BindTwoWayCodeGenerator.Generate(data.Left.Left, data.Left.Right, data.Right); - if (source == null) + if (source is null) { return; } diff --git a/src/ReactiveUI.Binding.SourceGenerators/Invocations/OneWayBindInvocationGenerator.cs b/src/ReactiveUI.Binding.SourceGenerators/Invocations/OneWayBindInvocationGenerator.cs index eaba4fe..7928659 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Invocations/OneWayBindInvocationGenerator.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Invocations/OneWayBindInvocationGenerator.cs @@ -9,25 +9,21 @@ namespace ReactiveUI.Binding.SourceGenerators.Invocations; -/// -/// Detects OneWayBind (view-first one-way binding) invocations and generates per-invocation binding code. -/// +/// Detects OneWayBind (view-first one-way binding) invocations and generates per-invocation binding code. internal static class OneWayBindInvocationGenerator { - /// - /// Registers the OneWayBind invocation detection pipeline. - /// + /// Registers the OneWayBind invocation detection pipeline. /// The generator initialization context. /// The shared type detection pipeline. /// The consumer compilation's C# language-feature snapshot. internal static void Register( - IncrementalGeneratorInitializationContext context, + in IncrementalGeneratorInitializationContext context, IncrementalValuesProvider allClasses, IncrementalValueProvider languageFeatures) { var invocations = context.SyntaxProvider .CreateSyntaxProvider( - static (node, ct) => RoslynHelpers.IsOneWayBindSpecificInvocation(node, ct), + RoslynHelpers.IsOneWayBindSpecificInvocation, BindingExtractor.ExtractBindInvocation) .Where(static x => x is not null) .Select(static (x, _) => x!); @@ -41,7 +37,7 @@ internal static void Register( static (ctx, data) => { var source = OneWayBindCodeGenerator.Generate(data.Left.Left, data.Left.Right, data.Right); - if (source == null) + if (source is null) { return; } diff --git a/src/ReactiveUI.Binding.SourceGenerators/Invocations/WhenAnyInvocationGenerator.cs b/src/ReactiveUI.Binding.SourceGenerators/Invocations/WhenAnyInvocationGenerator.cs index 342be73..08bbc61 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Invocations/WhenAnyInvocationGenerator.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Invocations/WhenAnyInvocationGenerator.cs @@ -16,14 +16,12 @@ namespace ReactiveUI.Binding.SourceGenerators.Invocations; /// internal static class WhenAnyInvocationGenerator { - /// - /// Registers the WhenAny invocation detection pipeline. - /// + /// Registers the WhenAny invocation detection pipeline. /// The generator initialization context. /// The shared type detection pipeline. /// The consumer compilation's C# language-feature snapshot. internal static void Register( - IncrementalGeneratorInitializationContext context, + in IncrementalGeneratorInitializationContext context, IncrementalValuesProvider allClasses, IncrementalValueProvider languageFeatures) { @@ -43,7 +41,7 @@ internal static void Register( static (ctx, data) => { var source = WhenAnyCodeGenerator.Generate(data.Left.Left, data.Left.Right, data.Right); - if (source == null) + if (source is null) { return; } diff --git a/src/ReactiveUI.Binding.SourceGenerators/Invocations/WhenAnyObservableInvocationGenerator.cs b/src/ReactiveUI.Binding.SourceGenerators/Invocations/WhenAnyObservableInvocationGenerator.cs index 0571675..8858f95 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Invocations/WhenAnyObservableInvocationGenerator.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Invocations/WhenAnyObservableInvocationGenerator.cs @@ -16,14 +16,12 @@ namespace ReactiveUI.Binding.SourceGenerators.Invocations; /// internal static class WhenAnyObservableInvocationGenerator { - /// - /// Registers the WhenAnyObservable invocation detection pipeline. - /// + /// Registers the WhenAnyObservable invocation detection pipeline. /// The generator initialization context. /// The shared type detection pipeline. /// The consumer compilation's C# language-feature snapshot. internal static void Register( - IncrementalGeneratorInitializationContext context, + in IncrementalGeneratorInitializationContext context, IncrementalValuesProvider allClasses, IncrementalValueProvider languageFeatures) { @@ -43,7 +41,7 @@ internal static void Register( static (ctx, data) => { var source = WhenAnyObservableCodeGenerator.Generate(data.Left.Left, data.Left.Right, data.Right); - if (source == null) + if (source is null) { return; } diff --git a/src/ReactiveUI.Binding.SourceGenerators/Invocations/WhenAnyValueInvocationGenerator.cs b/src/ReactiveUI.Binding.SourceGenerators/Invocations/WhenAnyValueInvocationGenerator.cs index d44c112..e62ddc2 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Invocations/WhenAnyValueInvocationGenerator.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Invocations/WhenAnyValueInvocationGenerator.cs @@ -15,14 +15,12 @@ namespace ReactiveUI.Binding.SourceGenerators.Invocations; /// internal static class WhenAnyValueInvocationGenerator { - /// - /// Registers the WhenAnyValue/WhenAny invocation detection pipeline. - /// + /// Registers the WhenAnyValue/WhenAny invocation detection pipeline. /// The generator initialization context. /// The shared type detection pipeline. /// The consumer compilation's C# language-feature snapshot. internal static void Register( - IncrementalGeneratorInitializationContext context, + in IncrementalGeneratorInitializationContext context, IncrementalValuesProvider allClasses, IncrementalValueProvider languageFeatures) { @@ -43,7 +41,7 @@ internal static void Register( { var source = ObservationCodeGenerator.Generate(data.Left.Left, data.Left.Right, data.Right, "WhenAnyValue"); - if (source == null) + if (source is null) { return; } diff --git a/src/ReactiveUI.Binding.SourceGenerators/Invocations/WhenChangedInvocationGenerator.cs b/src/ReactiveUI.Binding.SourceGenerators/Invocations/WhenChangedInvocationGenerator.cs index 30e0eaa..60e070c 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Invocations/WhenChangedInvocationGenerator.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Invocations/WhenChangedInvocationGenerator.cs @@ -9,19 +9,15 @@ namespace ReactiveUI.Binding.SourceGenerators.Invocations; -/// -/// Detects WhenChanged invocations (after-change) and generates per-invocation observation code. -/// +/// Detects WhenChanged invocations (after-change) and generates per-invocation observation code. internal static class WhenChangedInvocationGenerator { - /// - /// Registers the WhenChanged invocation detection pipeline. - /// + /// Registers the WhenChanged invocation detection pipeline. /// The generator initialization context. /// The shared type detection pipeline. /// The consumer compilation's C# language-feature snapshot. internal static void Register( - IncrementalGeneratorInitializationContext context, + in IncrementalGeneratorInitializationContext context, IncrementalValuesProvider allClasses, IncrementalValueProvider languageFeatures) { @@ -42,7 +38,7 @@ internal static void Register( { var source = ObservationCodeGenerator.Generate(data.Left.Left, data.Left.Right, data.Right, "WhenChanged"); - if (source == null) + if (source is null) { return; } diff --git a/src/ReactiveUI.Binding.SourceGenerators/Invocations/WhenChangingInvocationGenerator.cs b/src/ReactiveUI.Binding.SourceGenerators/Invocations/WhenChangingInvocationGenerator.cs index ef75832..e95b3d3 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Invocations/WhenChangingInvocationGenerator.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Invocations/WhenChangingInvocationGenerator.cs @@ -15,14 +15,12 @@ namespace ReactiveUI.Binding.SourceGenerators.Invocations; /// internal static class WhenChangingInvocationGenerator { - /// - /// Registers the WhenChanging invocation detection pipeline. - /// + /// Registers the WhenChanging invocation detection pipeline. /// The generator initialization context. /// The shared type detection pipeline. /// The consumer compilation's C# language-feature snapshot. internal static void Register( - IncrementalGeneratorInitializationContext context, + in IncrementalGeneratorInitializationContext context, IncrementalValuesProvider allClasses, IncrementalValueProvider languageFeatures) { @@ -43,7 +41,7 @@ internal static void Register( { var source = ObservationCodeGenerator.Generate(data.Left.Left, data.Left.Right, data.Right, "WhenChanging"); - if (source == null) + if (source is null) { return; } diff --git a/src/ReactiveUI.Binding.SourceGenerators/Models/EquatableArray.cs b/src/ReactiveUI.Binding.SourceGenerators/Models/EquatableArray.cs index 79c27fd..0fa3464 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Models/EquatableArray.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Models/EquatableArray.cs @@ -14,24 +14,16 @@ namespace ReactiveUI.Binding.SourceGenerators.Models; internal readonly struct EquatableArray : IEquatable>, IEnumerable where T : IEquatable { - /// - /// The multiplier used in the deterministic hash-combine loop. - /// + /// The multiplier used in the deterministic hash-combine loop. private const int HashMultiplier = 31; - /// - /// The underlying array, or null if default-constructed. - /// + /// The underlying array, or null if default-constructed. private readonly T[]? _array; - /// - /// Cached hash code computed once at construction. - /// + /// Cached hash code computed once at construction. private readonly int _cachedHashCode; - /// - /// Initializes a new instance of the struct. - /// + /// Initializes a new instance of the struct. /// The array to wrap. public EquatableArray(T[] array) { @@ -39,46 +31,36 @@ public EquatableArray(T[] array) _cachedHashCode = ComputeHashCode(array); } - /// - /// Gets the length of the array. - /// - public int Length => _array?.Length ?? 0; + /// Gets the length of the array. + internal int Length => _array?.Length ?? 0; - /// - /// Gets the element at the specified index. - /// + /// Gets the element at the specified index. /// The zero-based index of the element to get. - public T this[int index] => _array![index]; + internal T this[int index] => _array![index]; - /// - /// Determines whether two arrays are equal. - /// + /// Determines whether two arrays are equal. /// The first array to compare. /// The second array to compare. /// true if the arrays are equal; otherwise, false. public static bool operator ==(EquatableArray left, EquatableArray right) => left.Equals(right); - /// - /// Determines whether two arrays are not equal. - /// + /// Determines whether two arrays are not equal. /// The first array to compare. /// The second array to compare. /// true if the arrays are not equal; otherwise, false. public static bool operator !=(EquatableArray left, EquatableArray right) => !left.Equals(right); - /// - /// Indicates whether the current array is equal to another array. - /// + /// Indicates whether the current array is equal to another array. /// An array to compare with this array. /// true if the arrays are equal; otherwise, false. public bool Equals(EquatableArray other) { - if (_array == null && other._array == null) + if (_array is null && other._array is null) { return true; } - if (_array == null || other._array == null) + if (_array is null || other._array is null) { return false; } @@ -99,39 +81,29 @@ public bool Equals(EquatableArray other) return true; } - /// - /// Determines whether the specified object is equal to the current array. - /// + /// Determines whether the specified object is equal to the current array. /// The object to compare with the current array. /// true if the specified object is equal to the current array; otherwise, false. public override bool Equals(object? obj) => obj is EquatableArray other && Equals(other); - /// - /// Returns the cached hash code for this array. - /// + /// Returns the cached hash code for this array. /// A hash code for the current array. public override int GetHashCode() => _cachedHashCode; - /// - /// Returns an enumerator that iterates through the array. - /// + /// Returns an enumerator that iterates through the array. /// An enumerator for the array. public IEnumerator GetEnumerator() => ((_array ?? []) as IEnumerable).GetEnumerator(); - /// - /// Returns an enumerator that iterates through the array. - /// + /// Returns an enumerator that iterates through the array. /// An enumerator for the array. IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - /// - /// Computes a deterministic hash code for the given array. - /// + /// Computes a deterministic hash code for the given array. /// The array to hash. /// A hash code for the array. internal static int ComputeHashCode(T[]? array) { - if (array == null) + if (array is null) { return 0; } diff --git a/src/ReactiveUI.Binding.SourceGenerators/Plugins/CommandBinding/CommandPropertyBindingPlugin.cs b/src/ReactiveUI.Binding.SourceGenerators/Plugins/CommandBinding/CommandPropertyBindingPlugin.cs index 2a72e27..4b97313 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Plugins/CommandBinding/CommandPropertyBindingPlugin.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Plugins/CommandBinding/CommandPropertyBindingPlugin.cs @@ -22,9 +22,7 @@ namespace ReactiveUI.Binding.SourceGenerators.Plugins.CommandBinding; /// internal sealed class CommandPropertyBindingPlugin : ICommandBindingPlugin { - /// - /// The affinity score for the Command property binder (highest priority among command binding plugins). - /// + /// The affinity score for the Command property binder (highest priority among command binding plugins). private static readonly int CommandPropertyAffinity = BindingAffinity.Explicit; /// @@ -34,8 +32,8 @@ internal sealed class CommandPropertyBindingPlugin : ICommandBindingPlugin public bool RequiresCustomBinderFallback => false; /// - public bool CanHandle(BindCommandInvocationInfo inv) - => inv.HasCommandProperty; + public bool CanHandle(BindCommandInvocationInfo inv) => + inv.HasCommandProperty; /// public void EmitBinding( @@ -46,42 +44,14 @@ public void EmitBinding( { if (inv.HasCommandParameterProperty && inv.HasObservableParameter) { - // Command + CommandParameter + observable parameter variant - sb.AppendLine($$""" - - {{inv.ParameterTypeFullName}}{{(supportsNullable && inv.ParameterIsReferenceType ? "?" : string.Empty)}} __latestParam = default; - var __paramSub = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Subscribe( - withParameter, p => System.Threading.Volatile.Write(ref __latestParam, p)); - - var serial = new global::ReactiveUI.Binding.Observables.SerialDisposable(); - var __cmdSub = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Subscribe(commandObs, cmd => - { - serial.Disposable = global::ReactiveUI.Binding.Observables.EmptyDisposable.Instance; - {{controlAccess}}.Command = cmd; - var param = System.Threading.Volatile.Read(ref __latestParam); - {{controlAccess}}.CommandParameter = param; - if (cmd != null) - { - serial.Disposable = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Subscribe( - withParameter, p => - { - System.Threading.Volatile.Write(ref __latestParam, p); - {{controlAccess}}.CommandParameter = p; - }); - } - }); - return new global::ReactiveUI.Binding.Observables.CompositeDisposable2( - new global::ReactiveUI.Binding.Observables.CompositeDisposable2(__cmdSub, __paramSub), serial); - } - """); + EmitObservableParameterBinding(sb, inv, controlAccess, supportsNullable); } else if (inv.HasCommandParameterProperty && inv is { HasExpressionParameter: true, ParameterPropertyPath: not null }) { - // Command + CommandParameter + expression parameter variant var paramAccess = CodeGeneratorHelpers.BuildPropertyAccessChain("viewModel", inv.ParameterPropertyPath.Value); - sb.AppendLine($$""" + _ = sb.AppendLine($$""" var serial = new global::ReactiveUI.Binding.Observables.SerialDisposable(); var __cmdSub = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Subscribe(commandObs, cmd => @@ -97,7 +67,7 @@ public void EmitBinding( else { // Command only (no parameter, or no CommandParameter property) - sb.AppendLine($$""" + _ = sb.AppendLine($$""" var serial = new global::ReactiveUI.Binding.Observables.SerialDisposable(); var __cmdSub = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Subscribe(commandObs, cmd => @@ -110,4 +80,45 @@ public void EmitBinding( """); } } + + /// + /// Emits the binding for the variant that has both a CommandParameter property and an observable + /// parameter, which must track the latest parameter value and re-subscribe per command. + /// + /// The string builder to append to. + /// The BindCommand invocation info. + /// The access chain to the bound control. + /// Whether the target supports nullable reference types (C# 8+). + private static void EmitObservableParameterBinding( + StringBuilder sb, + BindCommandInvocationInfo inv, + string controlAccess, + bool supportsNullable) => + _ = sb.AppendLine($$""" + + {{inv.ParameterTypeFullName}}{{(supportsNullable && inv.ParameterIsReferenceType ? "?" : string.Empty)}} __latestParam = default; + var __paramSub = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Subscribe( + withParameter, p => System.Threading.Volatile.Write(ref __latestParam, p)); + + var serial = new global::ReactiveUI.Binding.Observables.SerialDisposable(); + var __cmdSub = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Subscribe(commandObs, cmd => + { + serial.Disposable = global::ReactiveUI.Binding.Observables.EmptyDisposable.Instance; + {{controlAccess}}.Command = cmd; + var param = System.Threading.Volatile.Read(ref __latestParam); + {{controlAccess}}.CommandParameter = param; + if (cmd != null) + { + serial.Disposable = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Subscribe( + withParameter, p => + { + System.Threading.Volatile.Write(ref __latestParam, p); + {{controlAccess}}.CommandParameter = p; + }); + } + }); + return new global::ReactiveUI.Binding.Observables.CompositeDisposable2( + new global::ReactiveUI.Binding.Observables.CompositeDisposable2(__cmdSub, __paramSub), serial); + } + """); } diff --git a/src/ReactiveUI.Binding.SourceGenerators/Plugins/CommandBinding/DefaultEventBindingPlugin.cs b/src/ReactiveUI.Binding.SourceGenerators/Plugins/CommandBinding/DefaultEventBindingPlugin.cs index 7300b09..88198a5 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Plugins/CommandBinding/DefaultEventBindingPlugin.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Plugins/CommandBinding/DefaultEventBindingPlugin.cs @@ -19,9 +19,7 @@ namespace ReactiveUI.Binding.SourceGenerators.Plugins.CommandBinding; /// internal sealed class DefaultEventBindingPlugin : ICommandBindingPlugin { - /// - /// The affinity score for the default-event binder (lowest priority among command binding plugins). - /// + /// The affinity score for the default-event binder (lowest priority among command binding plugins). private static readonly int DefaultEventAffinity = BindingAffinity.DefaultEvent; /// @@ -31,17 +29,15 @@ internal sealed class DefaultEventBindingPlugin : ICommandBindingPlugin public bool RequiresCustomBinderFallback => true; /// - public bool CanHandle(BindCommandInvocationInfo inv) - => inv.ResolvedEventName != null; + public bool CanHandle(BindCommandInvocationInfo inv) => + inv.ResolvedEventName is not null; /// public void EmitBinding( StringBuilder sb, BindCommandInvocationInfo inv, string controlAccess, - bool supportsNullable) - { - CommandEventBindingEmitter.EmitByParameterKind( + bool supportsNullable) => CommandEventBindingEmitter.EmitByParameterKind( sb, inv, controlAccess, @@ -49,11 +45,8 @@ public void EmitBinding( EmitWithObservableParameter, EmitWithExpressionParameter, EmitWithNoParameter); - } - /// - /// Emits event-only command binding with an observable parameter. - /// + /// Emits event-only command binding with an observable parameter. /// The string builder. /// The BindCommand invocation info. /// The control access chain. @@ -98,9 +91,7 @@ void __Handler({{CommandEventBindingEmitter.SenderType(supportsNullable)}} sende } """); - /// - /// Emits event-only command binding with an expression parameter. - /// + /// Emits event-only command binding with an expression parameter. /// The string builder. /// The BindCommand invocation info. /// The control access chain. @@ -142,9 +133,7 @@ void __Handler({{CommandEventBindingEmitter.SenderType(supportsNullable)}} sende } """); - /// - /// Emits event-only command binding with no parameter. - /// + /// Emits event-only command binding with no parameter. /// The string builder. /// The BindCommand invocation info. /// The control access chain. diff --git a/src/ReactiveUI.Binding.SourceGenerators/Plugins/CommandBinding/EventEnabledBindingPlugin.cs b/src/ReactiveUI.Binding.SourceGenerators/Plugins/CommandBinding/EventEnabledBindingPlugin.cs index 1d0bf11..1715581 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Plugins/CommandBinding/EventEnabledBindingPlugin.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Plugins/CommandBinding/EventEnabledBindingPlugin.cs @@ -20,9 +20,7 @@ namespace ReactiveUI.Binding.SourceGenerators.Plugins.CommandBinding; /// internal sealed class EventEnabledBindingPlugin : ICommandBindingPlugin { - /// - /// The affinity score for the event + Enabled binder. - /// + /// The affinity score for the event + Enabled binder. private static readonly int EventEnabledAffinity = BindingAffinity.EventEnabledControl; /// @@ -32,17 +30,15 @@ internal sealed class EventEnabledBindingPlugin : ICommandBindingPlugin public bool RequiresCustomBinderFallback => true; /// - public bool CanHandle(BindCommandInvocationInfo inv) - => inv.ResolvedEventName != null && inv.HasEnabledProperty; + public bool CanHandle(BindCommandInvocationInfo inv) => + inv.ResolvedEventName is not null && inv.HasEnabledProperty; /// public void EmitBinding( StringBuilder sb, BindCommandInvocationInfo inv, string controlAccess, - bool supportsNullable) - { - CommandEventBindingEmitter.EmitByParameterKind( + bool supportsNullable) => CommandEventBindingEmitter.EmitByParameterKind( sb, inv, controlAccess, @@ -50,11 +46,8 @@ public void EmitBinding( EmitWithObservableParameter, EmitWithExpressionParameter, EmitWithNoParameter); - } - /// - /// Emits event + Enabled binding with an observable parameter. - /// + /// Emits event + Enabled binding with an observable parameter. /// The string builder. /// The BindCommand invocation info. /// The control access chain. @@ -109,9 +102,7 @@ void __Handler({{CommandEventBindingEmitter.SenderType(supportsNullable)}} sende } """); - /// - /// Emits event + Enabled binding with an expression parameter. - /// + /// Emits event + Enabled binding with an expression parameter. /// The string builder. /// The BindCommand invocation info. /// The control access chain. @@ -162,9 +153,7 @@ void __Handler({{CommandEventBindingEmitter.SenderType(supportsNullable)}} sende } """); - /// - /// Emits event + Enabled binding with no parameter. - /// + /// Emits event + Enabled binding with no parameter. /// The string builder. /// The BindCommand invocation info. /// The control access chain. diff --git a/src/ReactiveUI.Binding.SourceGenerators/Plugins/CommandBindingPluginRegistry.cs b/src/ReactiveUI.Binding.SourceGenerators/Plugins/CommandBindingPluginRegistry.cs index 3e30ae7..ab86154 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Plugins/CommandBindingPluginRegistry.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Plugins/CommandBindingPluginRegistry.cs @@ -13,9 +13,7 @@ namespace ReactiveUI.Binding.SourceGenerators.Plugins; /// internal static class CommandBindingPluginRegistry { - /// - /// All command binding plugins sorted by affinity descending (highest priority first). - /// + /// All command binding plugins sorted by affinity descending (highest priority first). private static readonly ICommandBindingPlugin[] Plugins = [ new CommandPropertyBindingPlugin(), // Affinity 5 @@ -23,10 +21,7 @@ internal static class CommandBindingPluginRegistry new DefaultEventBindingPlugin() // Affinity 3 ]; - /// - /// Returns the highest-affinity plugin that can handle the given invocation, - /// or if no plugin matches. - /// + /// Returns the highest-affinity plugin that can handle the given invocation, or if no plugin matches. /// The BindCommand invocation info. /// The best matching plugin, or null. internal static ICommandBindingPlugin? GetBestPlugin(BindCommandInvocationInfo inv) diff --git a/src/ReactiveUI.Binding.SourceGenerators/Plugins/ICommandBindingPlugin.cs b/src/ReactiveUI.Binding.SourceGenerators/Plugins/ICommandBindingPlugin.cs index f9ba291..5e66b98 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Plugins/ICommandBindingPlugin.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Plugins/ICommandBindingPlugin.cs @@ -14,10 +14,7 @@ namespace ReactiveUI.Binding.SourceGenerators.Plugins; /// internal interface ICommandBindingPlugin { - /// - /// Gets the affinity score for this plugin. - /// Higher values win when multiple plugins can handle the same invocation. - /// + /// Gets the affinity score for this plugin. Higher values win when multiple plugins can handle the same invocation. int Affinity { get; } /// @@ -29,16 +26,12 @@ internal interface ICommandBindingPlugin /// bool RequiresCustomBinderFallback { get; } - /// - /// Determines whether this plugin can handle the given BindCommand invocation. - /// + /// Determines whether this plugin can handle the given BindCommand invocation. /// The BindCommand invocation info. /// True if this plugin can generate binding code for this invocation. bool CanHandle(BindCommandInvocationInfo inv); - /// - /// Emits the command binding code into the string builder. - /// + /// Emits the command binding code into the string builder. /// The string builder. /// The BindCommand invocation info. /// The control access chain expression. diff --git a/src/ReactiveUI.Binding.SourceGenerators/Plugins/IObservationPlugin.cs b/src/ReactiveUI.Binding.SourceGenerators/Plugins/IObservationPlugin.cs index d25a48d..dd587dd 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Plugins/IObservationPlugin.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Plugins/IObservationPlugin.cs @@ -21,14 +21,10 @@ internal interface IObservationPlugin /// int Affinity { get; } - /// - /// Gets the observation kind identifier (e.g., "INPC", "ReactiveObject", "WpfDP"). - /// + /// Gets the observation kind identifier (e.g., "INPC", "ReactiveObject", "WpfDP"). string ObservationKind { get; } - /// - /// Gets a value indicating whether this plugin supports before-change (PropertyChanging) observation. - /// + /// Gets a value indicating whether this plugin supports before-change (PropertyChanging) observation. bool SupportsBeforeChanged { get; } /// @@ -38,9 +34,7 @@ internal interface IObservationPlugin /// bool RequiresHelperClasses { get; } - /// - /// Determines whether this plugin can handle the given type based on ClassBindingInfo flags. - /// + /// Determines whether this plugin can handle the given type based on ClassBindingInfo flags. /// The type-level binding info. /// True if this plugin can generate observation code for this type. bool IsAMatch(ClassBindingInfo classInfo); @@ -71,9 +65,7 @@ void EmitShallowObservation( bool isBeforeChange, bool includeStartWith); - /// - /// Emits a shallow (single-segment) observation as a local variable declaration. - /// + /// Emits a shallow (single-segment) observation as a local variable declaration. /// The string builder to append to. /// The root variable name (e.g., "obj"). /// The property path segment. @@ -88,9 +80,7 @@ void EmitShallowObservationVariable( bool isBeforeChange, string varName); - /// - /// Emits the root segment of a deep chain observation as a local variable declaration. - /// + /// Emits the root segment of a deep chain observation as a local variable declaration. /// The string builder to append to. /// The root variable name (e.g., "obj"). /// The first property path segment. @@ -105,9 +95,7 @@ void EmitDeepChainRootSegment( bool isBeforeChange, string obsVarName); - /// - /// Emits an inner segment of a deep chain observation using Select/Switch re-subscription. - /// + /// Emits an inner segment of a deep chain observation using Select/Switch re-subscription. /// The string builder to append to. /// The previous segment's observable variable name. /// The current segment's observable variable name. @@ -122,10 +110,7 @@ void EmitDeepChainInnerSegment( PropertyPathSegment segment, bool isBeforeChange); - /// - /// Emits an inline observation variable for binding generators. - /// Used by BindOneWay/BindTwoWay for direct observation code. - /// + /// Emits an inline observation variable for binding generators. Used by BindOneWay/BindTwoWay for direct observation code. /// The string builder to append to. /// The root variable name (e.g., "source", "target"). /// The property path segment. diff --git a/src/ReactiveUI.Binding.SourceGenerators/Plugins/Observation/AndroidObservationPlugin.cs b/src/ReactiveUI.Binding.SourceGenerators/Plugins/Observation/AndroidObservationPlugin.cs index 627d56c..2b96d7e 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Plugins/Observation/AndroidObservationPlugin.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Plugins/Observation/AndroidObservationPlugin.cs @@ -33,10 +33,7 @@ namespace ReactiveUI.Binding.SourceGenerators.Plugins.Observation; /// internal sealed class AndroidObservationPlugin : IObservationPlugin { - /// - /// The affinity score for the Android View observation plugin - /// (matches ReactiveUI's AndroidObservableForWidgets). - /// + /// The affinity score for the Android View observation plugin (matches ReactiveUI's AndroidObservableForWidgets). private static readonly int AndroidAffinity = BindingAffinity.Explicit; /// @@ -94,9 +91,9 @@ public void EmitDeepChainRootSegment( string castTypeName, bool isBeforeChange, string obsVarName) => - sb.AppendLine( - $" var {obsVarName} = (global::System.IObservable<{segment.PropertyTypeFullName}>" + - $")new global::ReactiveUI.Binding.Observables.ReturnObservable<{segment.PropertyTypeFullName}>((({castTypeName}){rootVar}).{segment.PropertyName});"); + sb + .Append($" var {obsVarName} = (global::System.IObservable<{segment.PropertyTypeFullName}>") + .AppendLine($")new global::ReactiveUI.Binding.Observables.ReturnObservable<{segment.PropertyTypeFullName}>((({castTypeName}){rootVar}).{segment.PropertyName});"); /// public void EmitDeepChainInnerSegment( @@ -110,7 +107,7 @@ public void EmitDeepChainInnerSegment( var segType = segment.PropertyTypeFullName; var declType = segment.DeclaringTypeFullName; - sb.AppendLine() + _ = sb.AppendLine() .AppendLine($""" var {curVar} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Switch( global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({prevVar}, diff --git a/src/ReactiveUI.Binding.SourceGenerators/Plugins/Observation/INPCObservationPlugin.cs b/src/ReactiveUI.Binding.SourceGenerators/Plugins/Observation/INPCObservationPlugin.cs index f78b68b..7e460e2 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Plugins/Observation/INPCObservationPlugin.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Plugins/Observation/INPCObservationPlugin.cs @@ -13,16 +13,9 @@ namespace ReactiveUI.Binding.SourceGenerators.Plugins.Observation; /// Supports both after-change and before-change (if type also implements INotifyPropertyChanging). /// Generates PropertyObservable / PropertyChangingObservable from the runtime library. /// -[System.Diagnostics.CodeAnalysis.SuppressMessage( - "Minor Code Smell", - "S101:Types should be named in PascalCase", - Justification = "INPC is an established acronym (INotifyPropertyChanged) matching the ReactiveUI domain terminology.")] internal sealed class INPCObservationPlugin : IObservationPlugin { - /// - /// The affinity score for the INotifyPropertyChanged observation plugin - /// (matches ReactiveUI's INPCObservableForProperty). - /// + /// The affinity score for the INotifyPropertyChanged observation plugin (matches ReactiveUI's INPCObservableForProperty). private static readonly int INPCAffinity = BindingAffinity.Explicit; /// @@ -58,16 +51,18 @@ public void EmitShallowObservation( { if (isBeforeChange) { - sb.Append( - $"new global::ReactiveUI.Binding.Observables.PropertyChangingObservable<{segment.PropertyTypeFullName}>((" + - $"""global::System.ComponentModel.INotifyPropertyChanging){rootVar}, "{segment.PropertyName}", (""" + - $"global::System.ComponentModel.INotifyPropertyChanging __o) => (({castTypeName})__o).{segment.PropertyName})"); + _ = sb + .Append($"new global::ReactiveUI.Binding.Observables.PropertyChangingObservable<{segment.PropertyTypeFullName}>((") + .Append($"""global::System.ComponentModel.INotifyPropertyChanging){rootVar}, "{segment.PropertyName}", (""") + .Append($"global::System.ComponentModel.INotifyPropertyChanging __o) => (({castTypeName})__o).{segment.PropertyName})"); } else { - sb.Append( - $"""new global::ReactiveUI.Binding.Observables.PropertyObservable<{segment.PropertyTypeFullName}>({rootVar}, "{segment.PropertyName}", (""" + - $"global::System.ComponentModel.INotifyPropertyChanged __o) => (({castTypeName})__o).{segment.PropertyName}, {(includeStartWith ? "true" : "false")})"); + _ = sb + .Append($"""new global::ReactiveUI.Binding.Observables.PropertyObservable<{segment.PropertyTypeFullName}>({rootVar}, "{segment.PropertyName}", (""") + .Append($"global::System.ComponentModel.INotifyPropertyChanged __o) => (({castTypeName})__o).{segment.PropertyName}, ") + .Append(includeStartWith ? "true" : "false") + .Append(')'); } } @@ -128,7 +123,7 @@ public void EmitDeepChainInnerSegment( { var segType = segment.PropertyTypeFullName; - sb.AppendLine() + _ = sb.AppendLine() .AppendLine(isBeforeChange ? $""" var {curVar} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Switch( diff --git a/src/ReactiveUI.Binding.SourceGenerators/Plugins/Observation/KVOObservationPlugin.cs b/src/ReactiveUI.Binding.SourceGenerators/Plugins/Observation/KVOObservationPlugin.cs index efb41ae..9943456 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Plugins/Observation/KVOObservationPlugin.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Plugins/Observation/KVOObservationPlugin.cs @@ -27,10 +27,6 @@ namespace ReactiveUI.Binding.SourceGenerators.Plugins.Observation; /// for the subscription lifetime. /// /// -[System.Diagnostics.CodeAnalysis.SuppressMessage( - "Minor Code Smell", - "S101:Types should be named in PascalCase", - Justification = "KVO is an established acronym (Key-Value Observing) matching the ReactiveUI domain terminology.")] internal sealed class KVOObservationPlugin : IObservationPlugin { /// @@ -72,7 +68,7 @@ public void EmitShallowObservation( bool includeStartWith) { var keyPath = ToKvoKeyPath(segment.PropertyName, segment.PropertyTypeFullName); - sb.Append($"new __KVOObservable<{segment.PropertyTypeFullName}>(") + _ = sb.Append($"new __KVOObservable<{segment.PropertyTypeFullName}>(") .Append($"(global::Foundation.NSObject){rootVar}, ") .Append($"\"{keyPath}\", ") .Append($"(global::Foundation.NSObject __o) => (({castTypeName})__o).{segment.PropertyName}, ") @@ -92,7 +88,7 @@ public void EmitShallowObservationVariable( string varName) { var keyPath = ToKvoKeyPath(segment.PropertyName, segment.PropertyTypeFullName); - sb.Append($""" + _ = sb.Append($""" var {varName} = new __KVOObservable<{segment.PropertyTypeFullName}>( (global::Foundation.NSObject){rootVar}, "{keyPath}", @@ -112,7 +108,7 @@ public void EmitDeepChainRootSegment( string obsVarName) { var keyPath = ToKvoKeyPath(segment.PropertyName, segment.PropertyTypeFullName); - sb.AppendLine($""" + _ = sb.AppendLine($""" var {obsVarName} = (global::System.IObservable<{segment.PropertyTypeFullName}>)new __KVOObservable<{segment.PropertyTypeFullName}>( (global::Foundation.NSObject){rootVar}, "{keyPath}", @@ -135,7 +131,7 @@ public void EmitDeepChainInnerSegment( var declType = segment.DeclaringTypeFullName; var keyPath = ToKvoKeyPath(segment.PropertyName, segment.PropertyTypeFullName); - sb.AppendLine() + _ = sb.AppendLine() .AppendLine($""" var {curVar} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Switch( global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({prevVar}, @@ -159,7 +155,7 @@ public void EmitInlineObservationVariable( string varName) { var keyPath = ToKvoKeyPath(segment.PropertyName, segment.PropertyTypeFullName); - sb.AppendLine($""" + _ = sb.AppendLine($""" var {varName} = new __KVOObservable<{segment.PropertyTypeFullName}>( (global::Foundation.NSObject){rootVar}, "{keyPath}", @@ -169,10 +165,7 @@ public void EmitInlineObservationVariable( """); } - /// - /// Renders a boolean as the lowercase C# literal text (true/false) for emission - /// into generated source. - /// + /// Renders a boolean as the lowercase C# literal text (true/false) for emission into generated source. /// The boolean value. /// "true" or "false". private static string BoolLiteral(bool value) => value ? "true" : "false"; @@ -190,20 +183,13 @@ private static string ToKvoKeyPath(string propertyName, string propertyTypeFullN { if (propertyTypeFullName == "bool" && !propertyName.StartsWith("Is", StringComparison.Ordinal)) { - propertyName = "Is" + propertyName; - } - - if (propertyName.Length == 0) - { - return propertyName; + propertyName = $"Is{propertyName}"; } - return char.ToLowerInvariant(propertyName[0]) + propertyName.Substring(1); + return propertyName.Length == 0 ? propertyName : char.ToLowerInvariant(propertyName[0]) + propertyName[1..]; } - /// - /// Emits the __KVOObserver NSObject subclass that forwards ObserveValue callbacks. - /// + /// Emits the __KVOObserver NSObject subclass that forwards ObserveValue callbacks. /// The string builder. private static void EmitObserverClass(StringBuilder sb) => sb.AppendLine(""" @@ -232,13 +218,11 @@ public override void ObserveValue( } """); - /// - /// Emits the __KVOObservable<T> fused observable that wraps KVO add/remove observer calls. - /// + /// Emits the __KVOObservable<T> fused observable that wraps KVO add/remove observer calls. /// The string builder. private static void EmitObservableClass(StringBuilder sb) { - sb.AppendLine(""" + _ = sb.AppendLine(""" /// /// Fused observable for Apple KVO property observation. @@ -278,11 +262,17 @@ internal __KVOObservable( EmitSubscriptionClass(sb); } - /// - /// Emits the nested Subscription type of __KVOObservable<T> and the closing brace of the observable. - /// + /// Emits the nested Subscription type of __KVOObservable<T> and the closing brace of the observable. /// The string builder. - private static void EmitSubscriptionClass(StringBuilder sb) => + private static void EmitSubscriptionClass(StringBuilder sb) + { + EmitSubscriptionClassHead(sb); + EmitSubscriptionClassCallbacks(sb); + } + + /// Emits the subscription's fields and constructor, which registers the KVO observer. + /// The string builder to append to. + private static void EmitSubscriptionClassHead(StringBuilder sb) => sb.AppendLine(""" private sealed class Subscription : global::System.IDisposable @@ -316,6 +306,12 @@ internal Subscription(__KVOObservable parent, global::System.IObserver obs _hasValue = true; observer.OnNext(initial); } + """); + + /// Emits the subscription's value-changed callback and disposal. + /// The string builder to append to. + private static void EmitSubscriptionClassCallbacks(StringBuilder sb) => + sb.AppendLine(""" private void OnValueChanged() { diff --git a/src/ReactiveUI.Binding.SourceGenerators/Plugins/Observation/ReactiveObjectObservationPlugin.cs b/src/ReactiveUI.Binding.SourceGenerators/Plugins/Observation/ReactiveObjectObservationPlugin.cs index 8acf506..d793852 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Plugins/Observation/ReactiveObjectObservationPlugin.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Plugins/Observation/ReactiveObjectObservationPlugin.cs @@ -16,10 +16,7 @@ namespace ReactiveUI.Binding.SourceGenerators.Plugins.Observation; /// internal sealed class ReactiveObjectObservationPlugin : IObservationPlugin { - /// - /// The affinity score for the IReactiveObject observation plugin - /// (matches ReactiveUI's IROObservableForProperty). - /// + /// The affinity score for the IReactiveObject observation plugin (matches ReactiveUI's IROObservableForProperty). private static readonly int ReactiveObjectAffinity = BindingAffinity.ExactType; /// @@ -55,16 +52,18 @@ public void EmitShallowObservation( { if (isBeforeChange) { - sb.Append( - $"new global::ReactiveUI.Binding.Observables.PropertyChangingObservable<{segment.PropertyTypeFullName}>((" + - $"""global::System.ComponentModel.INotifyPropertyChanging){rootVar}, "{segment.PropertyName}", (""" + - $"global::System.ComponentModel.INotifyPropertyChanging __o) => (({castTypeName})__o).{segment.PropertyName})"); + _ = sb + .Append($"new global::ReactiveUI.Binding.Observables.PropertyChangingObservable<{segment.PropertyTypeFullName}>((") + .Append($"""global::System.ComponentModel.INotifyPropertyChanging){rootVar}, "{segment.PropertyName}", (""") + .Append($"global::System.ComponentModel.INotifyPropertyChanging __o) => (({castTypeName})__o).{segment.PropertyName})"); } else { - sb.Append( - $"""new global::ReactiveUI.Binding.Observables.PropertyObservable<{segment.PropertyTypeFullName}>({rootVar}, "{segment.PropertyName}", (""" + - $"global::System.ComponentModel.INotifyPropertyChanged __o) => (({castTypeName})__o).{segment.PropertyName}, {(includeStartWith ? "true" : "false")})"); + _ = sb + .Append($"""new global::ReactiveUI.Binding.Observables.PropertyObservable<{segment.PropertyTypeFullName}>({rootVar}, "{segment.PropertyName}", (""") + .Append($"global::System.ComponentModel.INotifyPropertyChanged __o) => (({castTypeName})__o).{segment.PropertyName}, ") + .Append(includeStartWith ? "true" : "false") + .Append(')'); } } @@ -125,7 +124,7 @@ public void EmitDeepChainInnerSegment( { var segType = segment.PropertyTypeFullName; - sb.AppendLine() + _ = sb.AppendLine() .AppendLine(isBeforeChange ? $""" var {curVar} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Switch( diff --git a/src/ReactiveUI.Binding.SourceGenerators/Plugins/Observation/WinFormsObservationPlugin.cs b/src/ReactiveUI.Binding.SourceGenerators/Plugins/Observation/WinFormsObservationPlugin.cs index f69bceb..b457ede 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Plugins/Observation/WinFormsObservationPlugin.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Plugins/Observation/WinFormsObservationPlugin.cs @@ -67,12 +67,12 @@ public void EmitShallowObservation( { if (isBeforeChange) { - sb.Append( + _ = sb.Append( $"new global::ReactiveUI.Binding.Observables.ReturnObservable<{segment.PropertyTypeFullName}>(default({segment.PropertyTypeFullName}))"); return; } - sb.Append($"new global::ReactiveUI.Binding.Observables.EventObservable<{segment.PropertyTypeFullName}>(") + _ = sb.Append($"new global::ReactiveUI.Binding.Observables.EventObservable<{segment.PropertyTypeFullName}>(") .Append($"__h => (({castTypeName}){rootVar}).{segment.PropertyName}Changed += __h, ") .Append($"__h => (({castTypeName}){rootVar}).{segment.PropertyName}Changed -= __h, ") .Append($"() => (({castTypeName}){rootVar}).{segment.PropertyName}, ") @@ -91,12 +91,12 @@ public void EmitShallowObservationVariable( { if (isBeforeChange) { - sb.Append( + _ = sb.Append( $" var {varName} = new global::ReactiveUI.Binding.Observables.ReturnObservable<{segment.PropertyTypeFullName}>(default({segment.PropertyTypeFullName}));"); return; } - sb.Append($""" + _ = sb.Append($""" var {varName} = new global::ReactiveUI.Binding.Observables.EventObservable<{segment.PropertyTypeFullName}>( __h => (({castTypeName}){rootVar}).{segment.PropertyName}Changed += __h, __h => (({castTypeName}){rootVar}).{segment.PropertyName}Changed -= __h, @@ -116,13 +116,13 @@ public void EmitDeepChainRootSegment( { if (isBeforeChange) { - sb.AppendLine( - $" var {obsVarName} = (global::System.IObservable<{segment.PropertyTypeFullName}>" + - $")new global::ReactiveUI.Binding.Observables.ReturnObservable<{segment.PropertyTypeFullName}>(default({segment.PropertyTypeFullName}));"); + _ = sb + .Append($" var {obsVarName} = (global::System.IObservable<{segment.PropertyTypeFullName}>") + .AppendLine($")new global::ReactiveUI.Binding.Observables.ReturnObservable<{segment.PropertyTypeFullName}>(default({segment.PropertyTypeFullName}));"); return; } - sb.AppendLine($""" + _ = sb.AppendLine($""" var {obsVarName} = (global::System.IObservable<{segment.PropertyTypeFullName}>)new global::ReactiveUI.Binding.Observables.EventObservable<{segment.PropertyTypeFullName}>( __h => (({castTypeName}){rootVar}).{segment.PropertyName}Changed += __h, __h => (({castTypeName}){rootVar}).{segment.PropertyName}Changed -= __h, @@ -145,7 +145,7 @@ public void EmitDeepChainInnerSegment( if (isBeforeChange) { - sb.AppendLine() + _ = sb.AppendLine() .AppendLine($""" var {curVar} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Switch( global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({prevVar}, @@ -155,7 +155,7 @@ public void EmitDeepChainInnerSegment( return; } - sb.AppendLine() + _ = sb.AppendLine() .AppendLine($""" var {curVar} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Switch( global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({prevVar}, diff --git a/src/ReactiveUI.Binding.SourceGenerators/Plugins/Observation/WinUIObservationPlugin.cs b/src/ReactiveUI.Binding.SourceGenerators/Plugins/Observation/WinUIObservationPlugin.cs index de7f4a3..361a4d5 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Plugins/Observation/WinUIObservationPlugin.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Plugins/Observation/WinUIObservationPlugin.cs @@ -61,12 +61,12 @@ public void EmitShallowObservation( { if (isBeforeChange) { - sb.Append( + _ = sb.Append( $"new global::ReactiveUI.Binding.Observables.ReturnObservable<{segment.PropertyTypeFullName}>(default({segment.PropertyTypeFullName}))"); return; } - sb.Append($"new __WinUIDPObservable<{segment.PropertyTypeFullName}>(") + _ = sb.Append($"new __WinUIDPObservable<{segment.PropertyTypeFullName}>(") .Append($"(global::Microsoft.UI.Xaml.DependencyObject){rootVar}, ") .Append($"{castTypeName}.{segment.PropertyName}Property, ") .Append( @@ -86,12 +86,12 @@ public void EmitShallowObservationVariable( { if (isBeforeChange) { - sb.Append( + _ = sb.Append( $" var {varName} = new global::ReactiveUI.Binding.Observables.ReturnObservable<{segment.PropertyTypeFullName}>(default({segment.PropertyTypeFullName}));"); return; } - sb.Append($""" + _ = sb.Append($""" var {varName} = new __WinUIDPObservable<{segment.PropertyTypeFullName}>( (global::Microsoft.UI.Xaml.DependencyObject){rootVar}, {castTypeName}.{segment.PropertyName}Property, @@ -111,13 +111,13 @@ public void EmitDeepChainRootSegment( { if (isBeforeChange) { - sb.AppendLine( - $" var {obsVarName} = (global::System.IObservable<{segment.PropertyTypeFullName}>" + - $")new global::ReactiveUI.Binding.Observables.ReturnObservable<{segment.PropertyTypeFullName}>(default({segment.PropertyTypeFullName}));"); + _ = sb + .Append($" var {obsVarName} = (global::System.IObservable<{segment.PropertyTypeFullName}>") + .AppendLine($")new global::ReactiveUI.Binding.Observables.ReturnObservable<{segment.PropertyTypeFullName}>(default({segment.PropertyTypeFullName}));"); return; } - sb.AppendLine($""" + _ = sb.AppendLine($""" var {obsVarName} = (global::System.IObservable<{segment.PropertyTypeFullName}>)new __WinUIDPObservable<{segment.PropertyTypeFullName}>( (global::Microsoft.UI.Xaml.DependencyObject){rootVar}, {castTypeName}.{segment.PropertyName}Property, @@ -140,7 +140,7 @@ public void EmitDeepChainInnerSegment( if (isBeforeChange) { - sb.AppendLine() + _ = sb.AppendLine() .AppendLine($""" var {curVar} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Switch( global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({prevVar}, @@ -150,7 +150,7 @@ public void EmitDeepChainInnerSegment( return; } - sb.AppendLine() + _ = sb.AppendLine() .AppendLine($""" var {curVar} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Switch( global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({prevVar}, @@ -179,9 +179,7 @@ public void EmitInlineObservationVariable( true); """); - /// - /// Emits the __WinUIDPObservable<T> class header (fields and constructor). - /// + /// Emits the __WinUIDPObservable<T> class header (fields and constructor). /// The string builder. private static void EmitObservableHeader(StringBuilder sb) => sb.AppendLine(""" @@ -216,7 +214,15 @@ internal __WinUIDPObservable( /// for the __WinUIDPObservable<T> observable, closing the outer class. /// /// The string builder. - private static void EmitSubscriptionClass(StringBuilder sb) => + private static void EmitSubscriptionClass(StringBuilder sb) + { + EmitSubscriptionClassHead(sb); + EmitSubscriptionClassCallbacks(sb); + } + + /// Emits the Subscribe method plus the subscription's fields and constructor. + /// The string builder to append to. + private static void EmitSubscriptionClassHead(StringBuilder sb) => sb.AppendLine(""" public global::System.IDisposable Subscribe(global::System.IObserver observer) @@ -246,6 +252,12 @@ internal Subscription(__WinUIDPObservable parent, global::System.IObserver _hasValue = true; observer.OnNext(initial); } + """); + + /// Emits the subscription's change callback and disposal, closing the observable class. + /// The string builder to append to. + private static void EmitSubscriptionClassCallbacks(StringBuilder sb) => + sb.AppendLine(""" private void OnPropertyChanged( global::Microsoft.UI.Xaml.DependencyObject sender, diff --git a/src/ReactiveUI.Binding.SourceGenerators/Plugins/Observation/WpfObservationPlugin.cs b/src/ReactiveUI.Binding.SourceGenerators/Plugins/Observation/WpfObservationPlugin.cs index aecaa38..72699d0 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Plugins/Observation/WpfObservationPlugin.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Plugins/Observation/WpfObservationPlugin.cs @@ -69,18 +69,16 @@ public void EmitShallowObservation( // but we emit ReturnObservable as a safe fallback. if (isBeforeChange) { - sb.Append( + _ = sb.Append( $"new global::ReactiveUI.Binding.Observables.ReturnObservable<{segment.PropertyTypeFullName}>(default({segment.PropertyTypeFullName}))"); return; } - sb.Append($"new global::ReactiveUI.Binding.Observables.EventObservable<{segment.PropertyTypeFullName}>(") - .Append( - $"__h => global::System.ComponentModel.DependencyPropertyDescriptor.FromProperty({castTypeName}.{segment.PropertyName}Property," + - $" typeof({castTypeName})).AddValueChanged({rootVar}, __h), ") - .Append( - $"__h => global::System.ComponentModel.DependencyPropertyDescriptor.FromProperty({castTypeName}.{segment.PropertyName}Property," + - $" typeof({castTypeName})).RemoveValueChanged({rootVar}, __h), ") + _ = sb.Append($"new global::ReactiveUI.Binding.Observables.EventObservable<{segment.PropertyTypeFullName}>(") + .Append($"__h => global::System.ComponentModel.DependencyPropertyDescriptor.FromProperty({castTypeName}.{segment.PropertyName}Property,") + .Append($" typeof({castTypeName})).AddValueChanged({rootVar}, __h), ") + .Append($"__h => global::System.ComponentModel.DependencyPropertyDescriptor.FromProperty({castTypeName}.{segment.PropertyName}Property,") + .Append($" typeof({castTypeName})).RemoveValueChanged({rootVar}, __h), ") .Append($"() => (({castTypeName}){rootVar}).{segment.PropertyName}, ") .Append(includeStartWith ? "true" : "false") .Append(')'); @@ -97,12 +95,12 @@ public void EmitShallowObservationVariable( { if (isBeforeChange) { - sb.Append( + _ = sb.Append( $" var {varName} = new global::ReactiveUI.Binding.Observables.ReturnObservable<{segment.PropertyTypeFullName}>(default({segment.PropertyTypeFullName}));"); return; } - sb.Append($""" + _ = sb.Append($""" var {varName} = new global::ReactiveUI.Binding.Observables.EventObservable<{segment.PropertyTypeFullName}>( __h => global::System.ComponentModel.DependencyPropertyDescriptor.FromProperty( {castTypeName}.{segment.PropertyName}Property, typeof({castTypeName})).AddValueChanged({rootVar}, __h), @@ -124,13 +122,13 @@ public void EmitDeepChainRootSegment( { if (isBeforeChange) { - sb.AppendLine( - $" var {obsVarName} = (global::System.IObservable<{segment.PropertyTypeFullName}>" + - $")new global::ReactiveUI.Binding.Observables.ReturnObservable<{segment.PropertyTypeFullName}>(default({segment.PropertyTypeFullName}));"); + _ = sb + .Append($" var {obsVarName} = (global::System.IObservable<{segment.PropertyTypeFullName}>") + .AppendLine($")new global::ReactiveUI.Binding.Observables.ReturnObservable<{segment.PropertyTypeFullName}>(default({segment.PropertyTypeFullName}));"); return; } - sb.AppendLine($""" + _ = sb.AppendLine($""" var {obsVarName} = (global::System.IObservable<{segment.PropertyTypeFullName}>)new global::ReactiveUI.Binding.Observables.EventObservable<{segment.PropertyTypeFullName}>( __h => global::System.ComponentModel.DependencyPropertyDescriptor.FromProperty( {castTypeName}.{segment.PropertyName}Property, typeof({castTypeName})).AddValueChanged({rootVar}, __h), @@ -156,7 +154,7 @@ public void EmitDeepChainInnerSegment( if (isBeforeChange) { // WPF DP does not support before-change; emit ReturnObservable for inner segments too - sb.AppendLine() + _ = sb.AppendLine() .AppendLine($""" var {curVar} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Switch( global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({prevVar}, @@ -166,7 +164,7 @@ public void EmitDeepChainInnerSegment( return; } - sb.AppendLine() + _ = sb.AppendLine() .AppendLine($""" var {curVar} = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Switch( global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select({prevVar}, diff --git a/src/ReactiveUI.Binding.SourceGenerators/Plugins/ObservationPluginRegistry.cs b/src/ReactiveUI.Binding.SourceGenerators/Plugins/ObservationPluginRegistry.cs index 594db24..c140fe5 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/Plugins/ObservationPluginRegistry.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/Plugins/ObservationPluginRegistry.cs @@ -29,14 +29,10 @@ internal static class ObservationPluginRegistry new WpfObservationPlugin() // Affinity 4 - WPF DependencyObject ]; - /// - /// Gets the total number of registered plugins. - /// + /// Gets the total number of registered plugins. internal static int Count => Plugins.Length; - /// - /// Gets the highest-affinity plugin that can handle the given type. - /// + /// Gets the highest-affinity plugin that can handle the given type. /// The type-level binding info. /// The best matching plugin, or if no plugin matches. internal static IObservationPlugin? GetBestPlugin(ClassBindingInfo classInfo) @@ -52,9 +48,7 @@ internal static class ObservationPluginRegistry return null; } - /// - /// Gets a plugin by its observation kind identifier. - /// + /// Gets a plugin by its observation kind identifier. /// The observation kind (e.g., "INPC", "WpfDP"). /// The matching plugin, or if not found. internal static IObservationPlugin? GetPluginByKind(string observationKind) @@ -70,9 +64,7 @@ internal static class ObservationPluginRegistry return null; } - /// - /// Gets the plugin at the specified index. - /// + /// Gets the plugin at the specified index. /// The zero-based index. /// The plugin at the specified index. internal static IObservationPlugin GetPlugin(int index) => Plugins[index]; diff --git a/src/ReactiveUI.Binding.SourceGenerators/ReactiveUI.Binding.SourceGenerators.csproj b/src/ReactiveUI.Binding.SourceGenerators/ReactiveUI.Binding.SourceGenerators.csproj index 80ca960..383468e 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/ReactiveUI.Binding.SourceGenerators.csproj +++ b/src/ReactiveUI.Binding.SourceGenerators/ReactiveUI.Binding.SourceGenerators.csproj @@ -28,9 +28,13 @@ PackagePath="build\ReactiveUI.Binding.SourceGenerators.props;buildTransitive\ReactiveUI.Binding.SourceGenerators.props"/> + - + diff --git a/src/ReactiveUI.Binding.SourceGenerators/RoslynHelpers.cs b/src/ReactiveUI.Binding.SourceGenerators/RoslynHelpers.cs index 1ef6a5c..4282592 100644 --- a/src/ReactiveUI.Binding.SourceGenerators/RoslynHelpers.cs +++ b/src/ReactiveUI.Binding.SourceGenerators/RoslynHelpers.cs @@ -14,104 +14,82 @@ namespace ReactiveUI.Binding.SourceGenerators; /// internal static class RoslynHelpers { - /// - /// Pipeline A predicate: detects class declarations with a base list (potential INPC, IRO, DP, etc.). - /// + /// Pipeline A predicate: detects class declarations with a base list (potential INPC, IRO, DP, etc.). /// The syntax node to check. /// Cancellation token. /// true if the node is a class with a base list; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static bool IsClassWithBaseList(SyntaxNode node, CancellationToken ct) - => node is ClassDeclarationSyntax { BaseList.Types.Count: > 0 }; + internal static bool IsClassWithBaseList(SyntaxNode node, CancellationToken ct) => + node is ClassDeclarationSyntax { BaseList.Types.Count: > 0 }; - /// - /// Pipeline B predicate: detects WhenChanged invocations. - /// + /// Pipeline B predicate: detects WhenChanged invocations. /// The syntax node to check. /// Cancellation token. /// true if the node is a WhenChanged invocation; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static bool IsWhenChangedInvocation(SyntaxNode node, CancellationToken ct) - => node is InvocationExpressionSyntax + internal static bool IsWhenChangedInvocation(SyntaxNode node, CancellationToken ct) => + node is InvocationExpressionSyntax invocation + && invocation.Expression is MemberAccessExpressionSyntax { - Expression: MemberAccessExpressionSyntax - { - Name.Identifier.Text: Constants.WhenChangedMethodName - } + Name.Identifier.Text: Constants.WhenChangedMethodName }; - /// - /// Pipeline B predicate: detects WhenChanging invocations. - /// + /// Pipeline B predicate: detects WhenChanging invocations. /// The syntax node to check. /// Cancellation token. /// true if the node is a WhenChanging invocation; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static bool IsWhenChangingInvocation(SyntaxNode node, CancellationToken ct) - => node is InvocationExpressionSyntax + internal static bool IsWhenChangingInvocation(SyntaxNode node, CancellationToken ct) => + node is InvocationExpressionSyntax invocation + && invocation.Expression is MemberAccessExpressionSyntax { - Expression: MemberAccessExpressionSyntax - { - Name.Identifier.Text: Constants.WhenChangingMethodName - } + Name.Identifier.Text: Constants.WhenChangingMethodName }; - /// - /// Pipeline B predicate: detects BindOneWay or BindTwoWay invocations. - /// + /// Pipeline B predicate: detects BindOneWay or BindTwoWay invocations. /// The syntax node to check. /// Cancellation token. /// true if the node is a bind invocation; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static bool IsBindInvocation(SyntaxNode node, CancellationToken ct) - => node is InvocationExpressionSyntax + internal static bool IsBindInvocation(SyntaxNode node, CancellationToken ct) => + node is InvocationExpressionSyntax invocation + && invocation.Expression is MemberAccessExpressionSyntax { - Expression: MemberAccessExpressionSyntax - { - Name.Identifier.Text: Constants.BindOneWayMethodName or Constants.BindTwoWayMethodName - or Constants.OneWayBindMethodName or Constants.BindMethodName - } + Name.Identifier.Text: Constants.BindOneWayMethodName or Constants.BindTwoWayMethodName + or Constants.OneWayBindMethodName or Constants.BindMethodName }; - /// - /// Checks if a syntax node is a Bind (view-first two-way) invocation specifically. - /// + /// Checks if a syntax node is a Bind (view-first two-way) invocation specifically. /// The syntax node to check. /// Cancellation token. /// true if the node is a Bind invocation; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static bool IsBindSpecificInvocation(SyntaxNode node, CancellationToken ct) - => IsBindInvocation(node, ct) && GetMemberAccessName(node) == Constants.BindMethodName; + internal static bool IsBindSpecificInvocation(SyntaxNode node, CancellationToken ct) => + IsBindInvocation(node, ct) && GetMemberAccessName(node) == Constants.BindMethodName; - /// - /// Checks if a syntax node is a BindOneWay invocation specifically. - /// + /// Checks if a syntax node is a BindOneWay invocation specifically. /// The syntax node to check. /// Cancellation token. /// true if the node is a BindOneWay invocation; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static bool IsBindOneWaySpecificInvocation(SyntaxNode node, CancellationToken ct) - => IsBindInvocation(node, ct) && GetMemberAccessName(node) == Constants.BindOneWayMethodName; + internal static bool IsBindOneWaySpecificInvocation(SyntaxNode node, CancellationToken ct) => + IsBindInvocation(node, ct) && GetMemberAccessName(node) == Constants.BindOneWayMethodName; - /// - /// Checks if a syntax node is a BindTwoWay invocation specifically. - /// + /// Checks if a syntax node is a BindTwoWay invocation specifically. /// The syntax node to check. /// Cancellation token. /// true if the node is a BindTwoWay invocation; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static bool IsBindTwoWaySpecificInvocation(SyntaxNode node, CancellationToken ct) - => IsBindInvocation(node, ct) && GetMemberAccessName(node) == Constants.BindTwoWayMethodName; + internal static bool IsBindTwoWaySpecificInvocation(SyntaxNode node, CancellationToken ct) => + IsBindInvocation(node, ct) && GetMemberAccessName(node) == Constants.BindTwoWayMethodName; - /// - /// Checks if a syntax node is a OneWayBind invocation specifically. - /// + /// Checks if a syntax node is a OneWayBind invocation specifically. /// The syntax node to check. /// Cancellation token. /// true if the node is a OneWayBind invocation; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static bool IsOneWayBindSpecificInvocation(SyntaxNode node, CancellationToken ct) - => IsBindInvocation(node, ct) && GetMemberAccessName(node) == Constants.OneWayBindMethodName; + internal static bool IsOneWayBindSpecificInvocation(SyntaxNode node, CancellationToken ct) => + IsBindInvocation(node, ct) && GetMemberAccessName(node) == Constants.OneWayBindMethodName; /// /// Extracts the method name from a member access invocation expression. @@ -120,109 +98,80 @@ internal static bool IsOneWayBindSpecificInvocation(SyntaxNode node, Cancellatio /// The syntax node (expected to be an InvocationExpressionSyntax). /// The method name, or null. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static string? GetMemberAccessName(SyntaxNode node) - { - if (node is not InvocationExpressionSyntax { Expression: MemberAccessExpressionSyntax memberAccess }) - { - return null; - } + internal static string? GetMemberAccessName(SyntaxNode node) => + node is not InvocationExpressionSyntax { Expression: MemberAccessExpressionSyntax memberAccess } + ? null + : memberAccess.Name.Identifier.Text; - return memberAccess.Name.Identifier.Text; - } - - /// - /// Pipeline B predicate: detects WhenAnyValue invocations only. - /// + /// Pipeline B predicate: detects WhenAnyValue invocations only. /// The syntax node to check. /// Cancellation token. /// true if the node is a WhenAnyValue invocation; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static bool IsWhenAnyValueInvocation(SyntaxNode node, CancellationToken ct) - => node is InvocationExpressionSyntax + internal static bool IsWhenAnyValueInvocation(SyntaxNode node, CancellationToken ct) => + node is InvocationExpressionSyntax invocation + && invocation.Expression is MemberAccessExpressionSyntax { - Expression: MemberAccessExpressionSyntax - { - Name.Identifier.Text: Constants.WhenAnyValueMethodName - } + Name.Identifier.Text: Constants.WhenAnyValueMethodName }; - /// - /// Pipeline B predicate: detects WhenAny invocations (with IObservedChange selector). - /// + /// Pipeline B predicate: detects WhenAny invocations (with IObservedChange selector). /// The syntax node to check. /// Cancellation token. /// true if the node is a WhenAny invocation; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static bool IsWhenAnyInvocation(SyntaxNode node, CancellationToken ct) - => node is InvocationExpressionSyntax + internal static bool IsWhenAnyInvocation(SyntaxNode node, CancellationToken ct) => + node is InvocationExpressionSyntax invocation + && invocation.Expression is MemberAccessExpressionSyntax { - Expression: MemberAccessExpressionSyntax - { - Name.Identifier.Text: Constants.WhenAnyMethodName - } + Name.Identifier.Text: Constants.WhenAnyMethodName }; - /// - /// Pipeline B predicate: detects WhenAnyObservable invocations. - /// + /// Pipeline B predicate: detects WhenAnyObservable invocations. /// The syntax node to check. /// Cancellation token. /// true if the node is a WhenAnyObservable invocation; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static bool IsWhenAnyObservableInvocation(SyntaxNode node, CancellationToken ct) - => node is InvocationExpressionSyntax + internal static bool IsWhenAnyObservableInvocation(SyntaxNode node, CancellationToken ct) => + node is InvocationExpressionSyntax invocation + && invocation.Expression is MemberAccessExpressionSyntax { - Expression: MemberAccessExpressionSyntax - { - Name.Identifier.Text: Constants.WhenAnyObservableMethodName - } + Name.Identifier.Text: Constants.WhenAnyObservableMethodName }; - /// - /// Pipeline B predicate: detects BindInteraction invocations. - /// + /// Pipeline B predicate: detects BindInteraction invocations. /// The syntax node to check. /// Cancellation token. /// true if the node is a BindInteraction invocation; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static bool IsBindInteractionInvocation(SyntaxNode node, CancellationToken ct) - => node is InvocationExpressionSyntax + internal static bool IsBindInteractionInvocation(SyntaxNode node, CancellationToken ct) => + node is InvocationExpressionSyntax invocation + && invocation.Expression is MemberAccessExpressionSyntax { - Expression: MemberAccessExpressionSyntax - { - Name.Identifier.Text: Constants.BindInteractionMethodName - } + Name.Identifier.Text: Constants.BindInteractionMethodName }; - /// - /// Pipeline B predicate: detects BindCommand invocations. - /// + /// Pipeline B predicate: detects BindCommand invocations. /// The syntax node to check. /// Cancellation token. /// true if the node is a BindCommand invocation; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static bool IsBindCommandInvocation(SyntaxNode node, CancellationToken ct) - => node is InvocationExpressionSyntax + internal static bool IsBindCommandInvocation(SyntaxNode node, CancellationToken ct) => + node is InvocationExpressionSyntax invocation + && invocation.Expression is MemberAccessExpressionSyntax { - Expression: MemberAccessExpressionSyntax - { - Name.Identifier.Text: Constants.BindCommandMethodName - } + Name.Identifier.Text: Constants.BindCommandMethodName }; - /// - /// Pipeline B predicate: detects BindTo invocations (observable stream to target property). - /// + /// Pipeline B predicate: detects BindTo invocations (observable stream to target property). /// The syntax node to check. /// Cancellation token. /// true if the node is a BindTo invocation; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static bool IsBindToInvocation(SyntaxNode node, CancellationToken ct) - => node is InvocationExpressionSyntax + internal static bool IsBindToInvocation(SyntaxNode node, CancellationToken ct) => + node is InvocationExpressionSyntax invocation + && invocation.Expression is MemberAccessExpressionSyntax { - Expression: MemberAccessExpressionSyntax - { - Name.Identifier.Text: Constants.BindToMethodName - } + Name.Identifier.Text: Constants.BindToMethodName }; } diff --git a/src/ReactiveUI.Binding.WinForms/Builder/WinFormsBindingBuilderExtensions.cs b/src/ReactiveUI.Binding.WinForms/Builder/WinFormsBindingBuilderExtensions.cs index 60e0da9..cc02904 100644 --- a/src/ReactiveUI.Binding.WinForms/Builder/WinFormsBindingBuilderExtensions.cs +++ b/src/ReactiveUI.Binding.WinForms/Builder/WinFormsBindingBuilderExtensions.cs @@ -7,30 +7,36 @@ namespace ReactiveUI.Binding.WinForms.Builder; -/// -/// WinForms-specific extensions for the ReactiveUI.Binding builder. -/// +/// WinForms-specific extensions for the ReactiveUI.Binding builder. public static class WinFormsBindingBuilderExtensions { - /// - /// Configures ReactiveUI.Binding for WinForms platform, registering event-based - /// property observation for WinForms components. - /// + /// Provides WithWinForms extension members for . /// The builder instance. - /// The builder instance for chaining. - public static IReactiveUIBindingBuilder WithWinForms(this IReactiveUIBindingBuilder builder) + extension(IAppBuilder builder) { - ArgumentExceptionHelper.ThrowIfNull(builder); - - return builder.WithPlatformModule(new WinFormsBindingModule()); + /// + /// Configures ReactiveUI.Binding for WinForms platform, registering event-based + /// property observation for WinForms components. + /// + /// The builder instance for chaining. + public IReactiveUIBindingBuilder WithWinForms() => + ((IReactiveUIBindingBuilder)builder).WithWinForms(); } - /// - /// Configures ReactiveUI.Binding for WinForms platform, registering event-based - /// property observation for WinForms components. - /// + /// Provides WithWinForms extension members for . /// The builder instance. - /// The builder instance for chaining. - public static IReactiveUIBindingBuilder WithWinForms(this IAppBuilder builder) => - ((IReactiveUIBindingBuilder)builder).WithWinForms(); + extension(IReactiveUIBindingBuilder builder) + { + /// + /// Configures ReactiveUI.Binding for WinForms platform, registering event-based + /// property observation for WinForms components. + /// + /// The builder instance for chaining. + public IReactiveUIBindingBuilder WithWinForms() + { + ArgumentExceptionHelper.ThrowIfNull(builder); + + return builder.WithPlatformModule(new WinFormsBindingModule()); + } + } } diff --git a/src/ReactiveUI.Binding.WinForms/WinFormsBindingModule.cs b/src/ReactiveUI.Binding.WinForms/WinFormsBindingModule.cs index 8037150..d28aada 100644 --- a/src/ReactiveUI.Binding.WinForms/WinFormsBindingModule.cs +++ b/src/ReactiveUI.Binding.WinForms/WinFormsBindingModule.cs @@ -6,9 +6,7 @@ namespace ReactiveUI.Binding.WinForms; -/// -/// WinForms-specific module that registers event-based property observation with the dependency resolver. -/// +/// WinForms-specific module that registers event-based property observation with the dependency resolver. /// /// WinForms command binding (event+Enabled) is handled at compile time by the source generator. /// @@ -19,6 +17,6 @@ public void Configure(IMutableDependencyResolver resolver) { ArgumentExceptionHelper.ThrowIfNull(resolver); - resolver.RegisterLazySingleton(() => new WinFormsCreatesObservableForProperty()); + resolver.RegisterLazySingleton(static () => new WinFormsCreatesObservableForProperty()); } } diff --git a/src/ReactiveUI.Binding.WinForms/WinFormsCreatesObservableForProperty.cs b/src/ReactiveUI.Binding.WinForms/WinFormsCreatesObservableForProperty.cs index 126d5c9..23386d9 100644 --- a/src/ReactiveUI.Binding.WinForms/WinFormsCreatesObservableForProperty.cs +++ b/src/ReactiveUI.Binding.WinForms/WinFormsCreatesObservableForProperty.cs @@ -7,10 +7,7 @@ namespace ReactiveUI.Binding.WinForms; -/// -/// Creates observables for WinForms component properties by subscribing to -/// {PropertyName}Changed events via reflection. -/// +/// Creates observables for WinForms component properties by subscribing to {PropertyName}Changed events via reflection. [RequiresUnreferencedCode( "Uses reflection to find and subscribe to {PropertyName}Changed events on WinForms components.")] public class WinFormsCreatesObservableForProperty : ICreatesObservableForProperty @@ -61,14 +58,13 @@ public int GetAffinityForObject(Type type, string propertyName, bool beforeChang subj.OnNext(new ObservedChange(sender, expression, default))); ei.AddEventHandler(sender, handler); - return Disposable.Create(() => ei.RemoveEventHandler(sender, handler)); + return Disposable.Create( + (ei, sender, handler), + static state => state.ei.RemoveEventHandler(state.sender, state.handler)); }); } - /// - /// Retrieves the for the specified {PropertyName}Changed event - /// on the given type. - /// + /// Retrieves the for the specified {PropertyName}Changed event on the given type. /// The type to be inspected for the event. /// The name of the property whose corresponding event information is to be retrieved. /// @@ -77,7 +73,7 @@ public int GetAffinityForObject(Type type, string propertyName, bool beforeChang internal static EventInfo? GetEventInfo(Type type, string propertyName) => EventInfoCache.GetOrAdd( (type, propertyName), - key => key.Type.GetEvent( - key.PropertyName + "Changed", + static key => key.Type.GetEvent( + $"{key.PropertyName}Changed", BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy)); } diff --git a/src/ReactiveUI.Binding.Wpf/BooleanToVisibilityHints.cs b/src/ReactiveUI.Binding.Wpf/BooleanToVisibilityHints.cs index 3ba4611..19d4795 100644 --- a/src/ReactiveUI.Binding.Wpf/BooleanToVisibilityHints.cs +++ b/src/ReactiveUI.Binding.Wpf/BooleanToVisibilityHints.cs @@ -4,24 +4,16 @@ namespace ReactiveUI.Binding.Wpf; -/// -/// Enum that hints at the visibility of a UI element. -/// +/// Enum that hints at the visibility of a UI element. [Flags] public enum BooleanToVisibilityHints { - /// - /// Do not modify the boolean type conversion from its default action of using Visibility.Collapsed. - /// + /// Do not modify the boolean type conversion from its default action of using Visibility.Collapsed. None = 0, - /// - /// Inverse the action of the boolean type conversion; when true, collapse the visibility. - /// + /// Inverse the action of the boolean type conversion; when true, collapse the visibility. Inverse = 1 << 1, - /// - /// Use Visibility.Hidden rather than Visibility.Collapsed for false values. - /// + /// Use Visibility.Hidden rather than Visibility.Collapsed for false values. UseHidden = 1 << 2 } diff --git a/src/ReactiveUI.Binding.Wpf/BooleanToVisibilityTypeConverter.cs b/src/ReactiveUI.Binding.Wpf/BooleanToVisibilityTypeConverter.cs index 0e56827..2ba8fd9 100644 --- a/src/ReactiveUI.Binding.Wpf/BooleanToVisibilityTypeConverter.cs +++ b/src/ReactiveUI.Binding.Wpf/BooleanToVisibilityTypeConverter.cs @@ -6,9 +6,7 @@ namespace ReactiveUI.Binding.Wpf; -/// -/// Converts to . -/// +/// Converts to . /// /// /// The conversion supports a as the conversion hint parameter: diff --git a/src/ReactiveUI.Binding.Wpf/Builder/WpfBindingBuilderExtensions.cs b/src/ReactiveUI.Binding.Wpf/Builder/WpfBindingBuilderExtensions.cs index 9703839..b389510 100644 --- a/src/ReactiveUI.Binding.Wpf/Builder/WpfBindingBuilderExtensions.cs +++ b/src/ReactiveUI.Binding.Wpf/Builder/WpfBindingBuilderExtensions.cs @@ -7,30 +7,36 @@ namespace ReactiveUI.Binding.Wpf.Builder; -/// -/// WPF-specific extensions for the ReactiveUI.Binding builder. -/// +/// WPF-specific extensions for the ReactiveUI.Binding builder. public static class WpfBindingBuilderExtensions { - /// - /// Configures ReactiveUI.Binding for WPF platform, registering DependencyObject observation - /// and WPF-specific Visibility converters. - /// + /// Provides WithWpf extension members for . /// The builder instance. - /// The builder instance for chaining. - public static IReactiveUIBindingBuilder WithWpf(this IReactiveUIBindingBuilder builder) + extension(IAppBuilder builder) { - ArgumentExceptionHelper.ThrowIfNull(builder); - - return builder.WithPlatformModule(new WpfBindingModule()); + /// + /// Configures ReactiveUI.Binding for WPF platform, registering DependencyObject observation + /// and WPF-specific Visibility converters. + /// + /// The builder instance for chaining. + public IReactiveUIBindingBuilder WithWpf() => + ((IReactiveUIBindingBuilder)builder).WithWpf(); } - /// - /// Configures ReactiveUI.Binding for WPF platform, registering DependencyObject observation - /// and WPF-specific Visibility converters. - /// + /// Provides WithWpf extension members for . /// The builder instance. - /// The builder instance for chaining. - public static IReactiveUIBindingBuilder WithWpf(this IAppBuilder builder) => - ((IReactiveUIBindingBuilder)builder).WithWpf(); + extension(IReactiveUIBindingBuilder builder) + { + /// + /// Configures ReactiveUI.Binding for WPF platform, registering DependencyObject observation + /// and WPF-specific Visibility converters. + /// + /// The builder instance for chaining. + public IReactiveUIBindingBuilder WithWpf() + { + ArgumentExceptionHelper.ThrowIfNull(builder); + + return builder.WithPlatformModule(new WpfBindingModule()); + } + } } diff --git a/src/ReactiveUI.Binding.Wpf/DependencyObjectObservableForProperty.cs b/src/ReactiveUI.Binding.Wpf/DependencyObjectObservableForProperty.cs index 2b61fc8..32c2cf1 100644 --- a/src/ReactiveUI.Binding.Wpf/DependencyObjectObservableForProperty.cs +++ b/src/ReactiveUI.Binding.Wpf/DependencyObjectObservableForProperty.cs @@ -7,9 +7,7 @@ namespace ReactiveUI.Binding.Wpf; -/// -/// Creates an observable for a property if available that is based on a WPF DependencyProperty. -/// +/// Creates an observable for a property if available that is based on a WPF DependencyProperty. public class DependencyObjectObservableForProperty : ICreatesObservableForProperty { /// @@ -48,7 +46,7 @@ public int GetAffinityForObject(Type type, string propertyName, bool beforeChang $"[ReactiveUI.Binding.Wpf] Error: Couldn't find dependency property {propertyName} on {type.Name}"); } - throw new InvalidOperationException("Couldn't find dependency property " + propertyName + " on " + type.Name); + throw new InvalidOperationException($"Couldn't find dependency property {propertyName} on {type.Name}"); } return Observable.Create>(subj => @@ -57,13 +55,13 @@ public int GetAffinityForObject(Type type, string propertyName, bool beforeChang subj.OnNext(new ObservedChange(sender, expression, default))); dependencyPropertyDescriptor.AddValueChanged(sender, handler); - return Disposable.Create(() => dependencyPropertyDescriptor.RemoveValueChanged(sender, handler)); + return Disposable.Create( + (dependencyPropertyDescriptor, sender, handler), + static state => state.dependencyPropertyDescriptor.RemoveValueChanged(state.sender, state.handler)); }); } - /// - /// Retrieves the associated with the specified property name on the given type, if available. - /// + /// Retrieves the associated with the specified property name on the given type, if available. /// The type to search for the dependency property. /// The name of the property for which the dependency property is sought. /// @@ -74,7 +72,7 @@ public int GetAffinityForObject(Type type, string propertyName, bool beforeChang { var fi = Array.Find( type.GetTypeInfo().GetFields(BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public), - x => x.Name == propertyName + "Property" && x.IsStatic); + x => x.Name == $"{propertyName}Property" && x.IsStatic); return (DependencyProperty?)fi?.GetValue(null); } diff --git a/src/ReactiveUI.Binding.Wpf/VisibilityToBooleanTypeConverter.cs b/src/ReactiveUI.Binding.Wpf/VisibilityToBooleanTypeConverter.cs index ba8d39d..6897f80 100644 --- a/src/ReactiveUI.Binding.Wpf/VisibilityToBooleanTypeConverter.cs +++ b/src/ReactiveUI.Binding.Wpf/VisibilityToBooleanTypeConverter.cs @@ -6,9 +6,7 @@ namespace ReactiveUI.Binding.Wpf; -/// -/// Converts to . -/// +/// Converts to . /// /// /// The conversion supports a as the conversion hint parameter: diff --git a/src/ReactiveUI.Binding.Wpf/WpfBindingModule.cs b/src/ReactiveUI.Binding.Wpf/WpfBindingModule.cs index 9e540f4..46e5d93 100644 --- a/src/ReactiveUI.Binding.Wpf/WpfBindingModule.cs +++ b/src/ReactiveUI.Binding.Wpf/WpfBindingModule.cs @@ -6,9 +6,7 @@ namespace ReactiveUI.Binding.Wpf; -/// -/// WPF-specific module that registers DependencyObject observation with the dependency resolver. -/// +/// WPF-specific module that registers DependencyObject observation with the dependency resolver. /// /// WPF command binding (via Command property) is handled at compile time by the source generator. /// @@ -19,7 +17,7 @@ public void Configure(IMutableDependencyResolver resolver) { ArgumentExceptionHelper.ThrowIfNull(resolver); - resolver.RegisterLazySingleton(() => + resolver.RegisterLazySingleton(static () => new DependencyObjectObservableForProperty()); } } diff --git a/src/ReactiveUI.Binding/Bindings/BindingTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/BindingTypeConverter.cs index 7976fd4..bc1d4cf 100644 --- a/src/ReactiveUI.Binding/Bindings/BindingTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/BindingTypeConverter.cs @@ -4,9 +4,7 @@ namespace ReactiveUI.Binding; -/// -/// Base class for type-pair binding converters. -/// +/// Base class for type-pair binding converters. /// The source type to convert from. /// The target type to convert to. /// @@ -22,9 +20,7 @@ public abstract class BindingTypeConverter : IBindingTypeConverter public Type ToType => typeof(TTo); - /// - /// Returns the affinity score for this converter. - /// + /// Returns the affinity score for this converter. /// /// A positive integer indicating converter priority. Higher values win when multiple converters match. /// Return 0 if the converter cannot handle the type pair. diff --git a/src/ReactiveUI.Binding/Bindings/BindingTypeConverterDispatch.cs b/src/ReactiveUI.Binding/Bindings/BindingTypeConverterDispatch.cs index 5ab7eac..4b53b12 100644 --- a/src/ReactiveUI.Binding/Bindings/BindingTypeConverterDispatch.cs +++ b/src/ReactiveUI.Binding/Bindings/BindingTypeConverterDispatch.cs @@ -4,15 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Dispatches conversions using a type-only fast-path, avoiding reflection. -/// +/// Dispatches conversions using a type-only fast-path, avoiding reflection. internal static class BindingTypeConverterDispatch { - /// - /// Attempts conversion via the converter's type-only metadata ( and - /// ) and object shim (). - /// + /// Attempts conversion via the converter's type-only metadata and its object shim. /// The converter. /// The source value. /// The target type requested by the caller. @@ -52,8 +47,8 @@ internal static bool TryConvert( // Exact pair match keeps dispatch predictable and avoids assignability ambiguity, // but allow nullable converters to accept boxed T values. - if (converterFromType != runtimeType && - Nullable.GetUnderlyingType(converterFromType) != runtimeType) + if (converterFromType != runtimeType + && Nullable.GetUnderlyingType(converterFromType) != runtimeType) { result = null; return false; @@ -62,9 +57,7 @@ internal static bool TryConvert( return converter.TryConvertTyped(from, conversionHint, out result); } - /// - /// Attempts conversion using a fallback converter. - /// + /// Attempts conversion using a fallback converter. /// The fallback converter. /// The source runtime type. /// The source value (guaranteed non-null by caller). @@ -74,14 +67,10 @@ internal static bool TryConvert( /// if conversion succeeded; otherwise, . internal static bool TryConvertFallback( IBindingFallbackConverter converter, -#if NET [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] -#endif Type fromType, object from, -#if NET [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] -#endif Type toType, object? conversionHint, out object? result) @@ -107,9 +96,7 @@ internal static bool TryConvertFallback( return false; } - /// - /// Unified dispatch method that handles both typed and fallback converters. - /// + /// Unified dispatch method that handles both typed and fallback converters. /// The converter (either or ). /// The source runtime type. /// The source value. @@ -126,14 +113,10 @@ internal static bool TryConvertFallback( /// internal static bool TryConvertAny( object? converter, -#if NET [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] -#endif Type fromType, object? from, -#if NET [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] -#endif Type toType, object? conversionHint, out object? result) diff --git a/src/ReactiveUI.Binding/Bindings/Converter/BooleanToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/BooleanToStringTypeConverter.cs index 95f865d..c86187f 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/BooleanToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/BooleanToStringTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to . -/// +/// Converts to . public sealed class BooleanToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/ByteToNullableByteTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/ByteToNullableByteTypeConverter.cs index 394d141..5b06d9e 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/ByteToNullableByteTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/ByteToNullableByteTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to . -/// +/// Converts to a nullable . public sealed class ByteToNullableByteTypeConverter : IBindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/ByteToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/ByteToStringTypeConverter.cs index ebf09db..9149765 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/ByteToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/ByteToStringTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts values to . -/// +/// Converts values to . public sealed class ByteToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/DateOnlyToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/DateOnlyToStringTypeConverter.cs index 80ab6cd..4afb9e6 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/DateOnlyToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/DateOnlyToStringTypeConverter.cs @@ -5,14 +5,10 @@ #if NET8_0_OR_GREATER namespace ReactiveUI.Binding; -/// -/// Converts to . -/// +/// Converts to . public sealed class DateOnlyToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/DateTimeOffsetToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/DateTimeOffsetToStringTypeConverter.cs index 2d396ad..b7f3021 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/DateTimeOffsetToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/DateTimeOffsetToStringTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to . -/// +/// Converts to . public sealed class DateTimeOffsetToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/DateTimeToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/DateTimeToStringTypeConverter.cs index 6d15f8d..ac8edbe 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/DateTimeToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/DateTimeToStringTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to . -/// +/// Converts to . public sealed class DateTimeToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/DecimalToNullableDecimalTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/DecimalToNullableDecimalTypeConverter.cs index 639df1f..7caf356 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/DecimalToNullableDecimalTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/DecimalToNullableDecimalTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to . -/// +/// Converts to a nullable . public sealed class DecimalToNullableDecimalTypeConverter : IBindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/DecimalToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/DecimalToStringTypeConverter.cs index 8b3c890..8bac275 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/DecimalToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/DecimalToStringTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts values to . -/// +/// Converts values to . public sealed class DecimalToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/DoubleToNullableDoubleTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/DoubleToNullableDoubleTypeConverter.cs index 0491aa1..92b7c7c 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/DoubleToNullableDoubleTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/DoubleToNullableDoubleTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to . -/// +/// Converts to a nullable . public sealed class DoubleToNullableDoubleTypeConverter : IBindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/DoubleToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/DoubleToStringTypeConverter.cs index 5820d44..96766a7 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/DoubleToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/DoubleToStringTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts values to . -/// +/// Converts values to . public sealed class DoubleToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/EqualityTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/EqualityTypeConverter.cs index d4bfd32..0de9961 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/EqualityTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/EqualityTypeConverter.cs @@ -4,9 +4,7 @@ namespace ReactiveUI.Binding; -/// -/// Converts any value to by comparing it with a hint value using . -/// +/// Converts any value to by comparing it with a hint value using . /// /// /// This converter is useful for binding scenarios where you need to determine if a value diff --git a/src/ReactiveUI.Binding/Bindings/Converter/GuidToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/GuidToStringTypeConverter.cs index 0f3f763..0c77af5 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/GuidToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/GuidToStringTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to using the "D" format (standard hyphenated format). -/// +/// Converts to using the "D" format (standard hyphenated format). public sealed class GuidToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/IntegerToNullableIntegerTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/IntegerToNullableIntegerTypeConverter.cs index f5c5fb6..f7685bf 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/IntegerToNullableIntegerTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/IntegerToNullableIntegerTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to . -/// +/// Converts to a nullable . public sealed class IntegerToNullableIntegerTypeConverter : IBindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/IntegerToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/IntegerToStringTypeConverter.cs index d1968b8..3acd3af 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/IntegerToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/IntegerToStringTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts values to . -/// +/// Converts values to . public sealed class IntegerToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/LongToNullableLongTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/LongToNullableLongTypeConverter.cs index 1d3b45c..003e759 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/LongToNullableLongTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/LongToNullableLongTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to . -/// +/// Converts to a nullable . public sealed class LongToNullableLongTypeConverter : IBindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/LongToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/LongToStringTypeConverter.cs index f99fbb5..96d455d 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/LongToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/LongToStringTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts values to . -/// +/// Converts values to . public sealed class LongToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/NullableBooleanToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/NullableBooleanToStringTypeConverter.cs index 6aeb4b0..0425786 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/NullableBooleanToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/NullableBooleanToStringTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts nullable to . -/// +/// Converts nullable to . public sealed class NullableBooleanToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/NullableByteToByteTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/NullableByteToByteTypeConverter.cs index 81e1454..a8e3832 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/NullableByteToByteTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/NullableByteToByteTypeConverter.cs @@ -4,17 +4,13 @@ namespace ReactiveUI.Binding; -/// -/// Converts to . -/// +/// Converts a nullable to . /// /// When the nullable value is null, the conversion fails and returns false. /// public sealed class NullableByteToByteTypeConverter : IBindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/NullableByteToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/NullableByteToStringTypeConverter.cs index 77cd8f2..5a812ea 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/NullableByteToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/NullableByteToStringTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts nullable values to . -/// +/// Converts nullable values to . public sealed class NullableByteToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/NullableDateOnlyToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/NullableDateOnlyToStringTypeConverter.cs index 07a6712..adbba26 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/NullableDateOnlyToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/NullableDateOnlyToStringTypeConverter.cs @@ -5,14 +5,10 @@ #if NET8_0_OR_GREATER namespace ReactiveUI.Binding; -/// -/// Converts nullable to . -/// +/// Converts nullable to . public sealed class NullableDateOnlyToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/NullableDateTimeOffsetToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/NullableDateTimeOffsetToStringTypeConverter.cs index 8bbbe92..b9d7afb 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/NullableDateTimeOffsetToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/NullableDateTimeOffsetToStringTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts nullable to . -/// +/// Converts nullable to . public sealed class NullableDateTimeOffsetToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/NullableDateTimeToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/NullableDateTimeToStringTypeConverter.cs index 6dda070..493bcc3 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/NullableDateTimeToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/NullableDateTimeToStringTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts nullable to . -/// +/// Converts nullable to . public sealed class NullableDateTimeToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/NullableDecimalToDecimalTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/NullableDecimalToDecimalTypeConverter.cs index 88bb177..19e1cc5 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/NullableDecimalToDecimalTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/NullableDecimalToDecimalTypeConverter.cs @@ -4,17 +4,13 @@ namespace ReactiveUI.Binding; -/// -/// Converts to . -/// +/// Converts a nullable to . /// /// When the nullable value is null, the conversion fails and returns false. /// public sealed class NullableDecimalToDecimalTypeConverter : IBindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/NullableDecimalToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/NullableDecimalToStringTypeConverter.cs index 2f7accf..2240a77 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/NullableDecimalToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/NullableDecimalToStringTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts nullable values to . -/// +/// Converts nullable values to . public sealed class NullableDecimalToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/NullableDoubleToDoubleTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/NullableDoubleToDoubleTypeConverter.cs index 56b50d1..9a06561 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/NullableDoubleToDoubleTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/NullableDoubleToDoubleTypeConverter.cs @@ -4,17 +4,13 @@ namespace ReactiveUI.Binding; -/// -/// Converts to . -/// +/// Converts a nullable to . /// /// When the nullable value is null, the conversion fails and returns false. /// public sealed class NullableDoubleToDoubleTypeConverter : IBindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/NullableDoubleToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/NullableDoubleToStringTypeConverter.cs index 250f8b7..de7216a 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/NullableDoubleToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/NullableDoubleToStringTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts nullable values to . -/// +/// Converts nullable values to . public sealed class NullableDoubleToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/NullableGuidToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/NullableGuidToStringTypeConverter.cs index fa05c80..36190d0 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/NullableGuidToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/NullableGuidToStringTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts nullable to using the "D" format (standard hyphenated format). -/// +/// Converts nullable to using the "D" format (standard hyphenated format). public sealed class NullableGuidToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/NullableIntegerToIntegerTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/NullableIntegerToIntegerTypeConverter.cs index 424d626..b15feba 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/NullableIntegerToIntegerTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/NullableIntegerToIntegerTypeConverter.cs @@ -4,17 +4,13 @@ namespace ReactiveUI.Binding; -/// -/// Converts to . -/// +/// Converts a nullable to . /// /// When the nullable value is null, the conversion fails and returns false. /// public sealed class NullableIntegerToIntegerTypeConverter : IBindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/NullableIntegerToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/NullableIntegerToStringTypeConverter.cs index 40d3e40..393ef1d 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/NullableIntegerToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/NullableIntegerToStringTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts nullable values to . -/// +/// Converts nullable values to . public sealed class NullableIntegerToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/NullableLongToLongTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/NullableLongToLongTypeConverter.cs index 22ca46a..b92420e 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/NullableLongToLongTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/NullableLongToLongTypeConverter.cs @@ -4,17 +4,13 @@ namespace ReactiveUI.Binding; -/// -/// Converts to . -/// +/// Converts a nullable to . /// /// When the nullable value is null, the conversion fails and returns false. /// public sealed class NullableLongToLongTypeConverter : IBindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/NullableLongToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/NullableLongToStringTypeConverter.cs index 2550b1d..27f7f42 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/NullableLongToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/NullableLongToStringTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts nullable values to . -/// +/// Converts nullable values to . public sealed class NullableLongToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/NullableShortToShortTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/NullableShortToShortTypeConverter.cs index 9fda063..fa31fe8 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/NullableShortToShortTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/NullableShortToShortTypeConverter.cs @@ -4,17 +4,13 @@ namespace ReactiveUI.Binding; -/// -/// Converts to . -/// +/// Converts a nullable to . /// /// When the nullable value is null, the conversion fails and returns false. /// public sealed class NullableShortToShortTypeConverter : IBindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/NullableShortToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/NullableShortToStringTypeConverter.cs index 5913e09..0dbbb74 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/NullableShortToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/NullableShortToStringTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts nullable values to . -/// +/// Converts nullable values to . public sealed class NullableShortToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/NullableSingleToSingleTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/NullableSingleToSingleTypeConverter.cs index b290e85..d6532e1 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/NullableSingleToSingleTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/NullableSingleToSingleTypeConverter.cs @@ -4,17 +4,13 @@ namespace ReactiveUI.Binding; -/// -/// Converts to . -/// +/// Converts a nullable to . /// /// When the nullable value is null, the conversion fails and returns false. /// public sealed class NullableSingleToSingleTypeConverter : IBindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/NullableSingleToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/NullableSingleToStringTypeConverter.cs index 4926995..4ea9347 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/NullableSingleToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/NullableSingleToStringTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts nullable values to . -/// +/// Converts nullable values to . public sealed class NullableSingleToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/NullableTimeOnlyToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/NullableTimeOnlyToStringTypeConverter.cs index e01affd..5980b7c 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/NullableTimeOnlyToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/NullableTimeOnlyToStringTypeConverter.cs @@ -5,14 +5,10 @@ #if NET8_0_OR_GREATER namespace ReactiveUI.Binding; -/// -/// Converts nullable to . -/// +/// Converts nullable to . public sealed class NullableTimeOnlyToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/NullableTimeSpanToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/NullableTimeSpanToStringTypeConverter.cs index 8bbc9da..a9538a2 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/NullableTimeSpanToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/NullableTimeSpanToStringTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts nullable to . -/// +/// Converts nullable to . public sealed class NullableTimeSpanToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/ShortToNullableShortTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/ShortToNullableShortTypeConverter.cs index bb4946a..fb5471c 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/ShortToNullableShortTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/ShortToNullableShortTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to . -/// +/// Converts to a nullable . public sealed class ShortToNullableShortTypeConverter : IBindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/ShortToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/ShortToStringTypeConverter.cs index b753987..5d87907 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/ShortToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/ShortToStringTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts values to . -/// +/// Converts values to . public sealed class ShortToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/SingleToNullableSingleTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/SingleToNullableSingleTypeConverter.cs index 2500470..b2f8250 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/SingleToNullableSingleTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/SingleToNullableSingleTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to . -/// +/// Converts to a nullable . public sealed class SingleToNullableSingleTypeConverter : IBindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/SingleToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/SingleToStringTypeConverter.cs index 11e624f..cf373a6 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/SingleToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/SingleToStringTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts values to . -/// +/// Converts values to . public sealed class SingleToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringConverter.cs index da19add..a7374d9 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringConverter.cs @@ -4,18 +4,14 @@ namespace ReactiveUI.Binding; -/// -/// Converts to (identity converter). -/// +/// Converts to (identity converter). /// /// This converter provides a fast path for string-to-string bindings without /// requiring reflection or TypeDescriptor. /// public sealed class StringConverter : IBindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToBooleanTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToBooleanTypeConverter.cs index 029d496..b2d8689 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToBooleanTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToBooleanTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to using . -/// +/// Converts to using . public sealed class StringToBooleanTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToByteTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToByteTypeConverter.cs index 01ede0d..90dfd42 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToByteTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToByteTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to using . -/// +/// Converts to using . public sealed class StringToByteTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToDateOnlyTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToDateOnlyTypeConverter.cs index 26f958f..80289e0 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToDateOnlyTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToDateOnlyTypeConverter.cs @@ -5,14 +5,10 @@ #if NET8_0_OR_GREATER namespace ReactiveUI.Binding; -/// -/// Converts to using . -/// +/// Converts to using . public sealed class StringToDateOnlyTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToDateTimeOffsetTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToDateTimeOffsetTypeConverter.cs index dd80028..cc45a01 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToDateTimeOffsetTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToDateTimeOffsetTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to using . -/// +/// Converts to using . public sealed class StringToDateTimeOffsetTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToDateTimeTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToDateTimeTypeConverter.cs index 2d1ee7f..29a8f35 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToDateTimeTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToDateTimeTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to using . -/// +/// Converts to using . public sealed class StringToDateTimeTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToDecimalTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToDecimalTypeConverter.cs index 0500148..f0a91dc 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToDecimalTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToDecimalTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to using . -/// +/// Converts to using . public sealed class StringToDecimalTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToDoubleTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToDoubleTypeConverter.cs index 350e8eb..ecad831 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToDoubleTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToDoubleTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to using . -/// +/// Converts to using . public sealed class StringToDoubleTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToGuidTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToGuidTypeConverter.cs index 96fc7a7..24aa9cd 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToGuidTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToGuidTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to using . -/// +/// Converts to using . public sealed class StringToGuidTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToIntegerTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToIntegerTypeConverter.cs index bdf3c8b..be51863 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToIntegerTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToIntegerTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to using . -/// +/// Converts to using . public sealed class StringToIntegerTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToLongTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToLongTypeConverter.cs index c479ce5..cf099f9 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToLongTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToLongTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to using . -/// +/// Converts to using . public sealed class StringToLongTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableBooleanTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableBooleanTypeConverter.cs index d7d194e..6ed2bd1 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableBooleanTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableBooleanTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to nullable using . -/// +/// Converts to nullable using . public sealed class StringToNullableBooleanTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableByteTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableByteTypeConverter.cs index 90d252d..3556864 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableByteTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableByteTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to nullable using . -/// +/// Converts to nullable using . public sealed class StringToNullableByteTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableDateOnlyTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableDateOnlyTypeConverter.cs index 8bbee1f..c3fc615 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableDateOnlyTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableDateOnlyTypeConverter.cs @@ -5,14 +5,10 @@ #if NET8_0_OR_GREATER namespace ReactiveUI.Binding; -/// -/// Converts to nullable using . -/// +/// Converts to nullable using . public sealed class StringToNullableDateOnlyTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableDateTimeOffsetTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableDateTimeOffsetTypeConverter.cs index 8f04d9f..2b54be2 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableDateTimeOffsetTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableDateTimeOffsetTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to nullable using . -/// +/// Converts to nullable using . public sealed class StringToNullableDateTimeOffsetTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableDateTimeTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableDateTimeTypeConverter.cs index 52adba6..4a8c36d 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableDateTimeTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableDateTimeTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to nullable using . -/// +/// Converts to nullable using . public sealed class StringToNullableDateTimeTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableDecimalTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableDecimalTypeConverter.cs index df98871..cd8910f 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableDecimalTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableDecimalTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to nullable using . -/// +/// Converts to nullable using . public sealed class StringToNullableDecimalTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableDoubleTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableDoubleTypeConverter.cs index 574d3b0..266d654 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableDoubleTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableDoubleTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to nullable using . -/// +/// Converts to nullable using . public sealed class StringToNullableDoubleTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableGuidTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableGuidTypeConverter.cs index 2af54b2..8feceaf 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableGuidTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableGuidTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to nullable using . -/// +/// Converts to nullable using . public sealed class StringToNullableGuidTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableIntegerTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableIntegerTypeConverter.cs index 1ee3bbb..9e47710 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableIntegerTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableIntegerTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to nullable using . -/// +/// Converts to nullable using . public sealed class StringToNullableIntegerTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableLongTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableLongTypeConverter.cs index 1d32693..00bac51 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableLongTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableLongTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to nullable using . -/// +/// Converts to nullable using . public sealed class StringToNullableLongTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableShortTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableShortTypeConverter.cs index 92dc81d..7dbea0e 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableShortTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableShortTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to nullable using . -/// +/// Converts to nullable using . public sealed class StringToNullableShortTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableSingleTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableSingleTypeConverter.cs index 18efd83..8524a3a 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableSingleTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableSingleTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to nullable using . -/// +/// Converts to nullable using . public sealed class StringToNullableSingleTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableTimeOnlyTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableTimeOnlyTypeConverter.cs index fe141f9..e1caf40 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableTimeOnlyTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableTimeOnlyTypeConverter.cs @@ -5,14 +5,10 @@ #if NET8_0_OR_GREATER namespace ReactiveUI.Binding; -/// -/// Converts to nullable using . -/// +/// Converts to nullable using . public sealed class StringToNullableTimeOnlyTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableTimeSpanTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableTimeSpanTypeConverter.cs index 66f7585..62696e7 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableTimeSpanTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToNullableTimeSpanTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to nullable using . -/// +/// Converts to nullable using . public sealed class StringToNullableTimeSpanTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToShortTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToShortTypeConverter.cs index abf017f..7a5bdb8 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToShortTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToShortTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to using . -/// +/// Converts to using . public sealed class StringToShortTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToSingleTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToSingleTypeConverter.cs index f535def..658df7f 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToSingleTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToSingleTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to using . -/// +/// Converts to using . public sealed class StringToSingleTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToTimeOnlyTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToTimeOnlyTypeConverter.cs index 0eabfa2..8fca3d6 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToTimeOnlyTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToTimeOnlyTypeConverter.cs @@ -5,14 +5,10 @@ #if NET8_0_OR_GREATER namespace ReactiveUI.Binding; -/// -/// Converts to using . -/// +/// Converts to using . public sealed class StringToTimeOnlyTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToTimeSpanTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToTimeSpanTypeConverter.cs index 8145e60..914e159 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToTimeSpanTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToTimeSpanTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to using . -/// +/// Converts to using . public sealed class StringToTimeSpanTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/StringToUriTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/StringToUriTypeConverter.cs index 95b9a24..7e322f1 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/StringToUriTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/StringToUriTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to using . -/// +/// Converts to using . public sealed class StringToUriTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/TimeOnlyToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/TimeOnlyToStringTypeConverter.cs index e067df0..69c7206 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/TimeOnlyToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/TimeOnlyToStringTypeConverter.cs @@ -5,14 +5,10 @@ #if NET8_0_OR_GREATER namespace ReactiveUI.Binding; -/// -/// Converts to . -/// +/// Converts to . public sealed class TimeOnlyToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/TimeSpanToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/TimeSpanToStringTypeConverter.cs index aec3612..da4954c 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/TimeSpanToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/TimeSpanToStringTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to . -/// +/// Converts to . public sealed class TimeSpanToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converter/UriToStringTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/Converter/UriToStringTypeConverter.cs index cf4152c..5cee430 100644 --- a/src/ReactiveUI.Binding/Bindings/Converter/UriToStringTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/Converter/UriToStringTypeConverter.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Converts to . -/// +/// Converts to . public sealed class UriToStringTypeConverter : BindingTypeConverter { - /// - /// The affinity returned by indicating a strong match. - /// + /// The affinity returned by indicating a strong match. private static readonly int Affinity = BindingAffinity.DefaultInternalTypeConverter; /// diff --git a/src/ReactiveUI.Binding/Bindings/Converters/BindingConverters.cs b/src/ReactiveUI.Binding/Bindings/Converters/BindingConverters.cs index 1744d06..79f6281 100644 --- a/src/ReactiveUI.Binding/Bindings/Converters/BindingConverters.cs +++ b/src/ReactiveUI.Binding/Bindings/Converters/BindingConverters.cs @@ -4,9 +4,7 @@ namespace ReactiveUI.Binding; -/// -/// Provides static access to the ReactiveUI.Binding converter service. -/// +/// Provides static access to the ReactiveUI.Binding converter service. /// /// /// This class provides a global access point to the instance @@ -15,9 +13,7 @@ namespace ReactiveUI.Binding; /// /// Custom Converter Registration: /// -/// -/// BindingConverters.Current.TypedConverters.Register(new MyCustomConverter()); -/// +/// BindingConverters.Current.TypedConverters.Register(new MyCustomConverter()); /// /// /// @@ -36,22 +32,16 @@ namespace ReactiveUI.Binding; /// public static class BindingConverters { - /// - /// The backing field for the current converter service instance. - /// + /// The backing field for the current converter service instance. private static ConverterService _current = new(); - /// - /// Gets the current converter service instance. - /// + /// Gets the current converter service instance. /// /// The instance used by ReactiveUI.Binding. /// public static ConverterService Current => _current; - /// - /// Sets the converter service instance. - /// + /// Sets the converter service instance. /// The converter service to use. Must not be null. /// Thrown if is null. /// diff --git a/src/ReactiveUI.Binding/Bindings/Converters/BindingFallbackConverterRegistry.cs b/src/ReactiveUI.Binding/Bindings/Converters/BindingFallbackConverterRegistry.cs index bb5ab19..5c82e9b 100644 --- a/src/ReactiveUI.Binding/Bindings/Converters/BindingFallbackConverterRegistry.cs +++ b/src/ReactiveUI.Binding/Bindings/Converters/BindingFallbackConverterRegistry.cs @@ -4,9 +4,7 @@ namespace ReactiveUI.Binding; -/// -/// Thread-safe registry for fallback binding converters using a lock-free snapshot pattern. -/// +/// Thread-safe registry for fallback binding converters using a lock-free snapshot pattern. /// /// /// This registry uses a copy-on-write snapshot pattern optimized for read-heavy workloads: @@ -34,23 +32,13 @@ namespace ReactiveUI.Binding; /// public sealed class BindingFallbackConverterRegistry { - /// - /// Synchronization gate for serializing write operations. - /// -#if NET9_0_OR_GREATER + /// Synchronization gate for serializing write operations. private readonly Lock _gate = new(); -#else - private readonly object _gate = new(); -#endif - /// - /// The current immutable snapshot of registered fallback converters, read via volatile access. - /// + /// The current immutable snapshot of registered fallback converters, read via volatile access. private Snapshot? _snapshot; - /// - /// Registers a fallback binding converter. - /// + /// Registers a fallback binding converter. /// The converter to register. Must not be null. /// Thrown if is null. /// @@ -64,9 +52,11 @@ public void Register(IBindingFallbackConverter converter) { ArgumentExceptionHelper.ThrowIfNull(converter); + const int InitialRegistryCapacity = 8; + lock (_gate) { - var snap = _snapshot ?? new Snapshot(new(8)); + var snap = _snapshot ?? new Snapshot(new(InitialRegistryCapacity)); // Copy-on-write update: clone the list var newList = new List(snap.Converters) { converter }; @@ -76,9 +66,7 @@ public void Register(IBindingFallbackConverter converter) } } - /// - /// Attempts to retrieve the best fallback converter for the specified type pair. - /// + /// Attempts to retrieve the best fallback converter for the specified type pair. /// The source type to convert from. /// The target type to convert to. /// @@ -88,13 +76,9 @@ public void Register(IBindingFallbackConverter converter) /// Thrown if or is null. /// public IBindingFallbackConverter? TryGetConverter( -#if NET [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] -#endif Type fromType, -#if NET [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] -#endif Type toType) { ArgumentExceptionHelper.ThrowIfNull(fromType); @@ -125,9 +109,7 @@ public void Register(IBindingFallbackConverter converter) return best; } - /// - /// Returns all registered fallback converters. - /// + /// Returns all registered fallback converters. /// /// A sequence of all fallback converters currently registered in the registry. /// Returns an empty sequence if no converters are registered. @@ -135,17 +117,10 @@ public void Register(IBindingFallbackConverter converter) public IEnumerable GetAllConverters() { var snap = Volatile.Read(ref _snapshot); - if (snap is null) - { - return []; - } - - return [.. snap.Converters]; + return snap is null ? [] : [.. snap.Converters]; } - /// - /// Immutable snapshot of the registry state for lock-free reads. - /// + /// Immutable snapshot of the registry state for lock-free reads. /// The registered fallback converters. private sealed record Snapshot(List Converters); } diff --git a/src/ReactiveUI.Binding/Bindings/Converters/BindingTypeConverterRegistry.cs b/src/ReactiveUI.Binding/Bindings/Converters/BindingTypeConverterRegistry.cs index b1bc82a..57c1798 100644 --- a/src/ReactiveUI.Binding/Bindings/Converters/BindingTypeConverterRegistry.cs +++ b/src/ReactiveUI.Binding/Bindings/Converters/BindingTypeConverterRegistry.cs @@ -4,9 +4,7 @@ namespace ReactiveUI.Binding; -/// -/// Thread-safe registry for typed binding converters using a lock-free snapshot pattern. -/// +/// Thread-safe registry for typed binding converters using a lock-free snapshot pattern. /// /// /// This registry uses a copy-on-write snapshot pattern optimized for read-heavy workloads: @@ -32,23 +30,13 @@ namespace ReactiveUI.Binding; /// public sealed class BindingTypeConverterRegistry { - /// - /// Synchronization gate for serializing write operations. - /// -#if NET9_0_OR_GREATER + /// Synchronization gate for serializing write operations. private readonly Lock _gate = new(); -#else - private readonly object _gate = new(); -#endif - /// - /// The current immutable snapshot of registered typed converters, read via volatile access. - /// + /// The current immutable snapshot of registered typed converters, read via volatile access. private Snapshot? _snapshot; - /// - /// Registers a typed binding converter. - /// + /// Registers a typed binding converter. /// The converter to register. Must not be null. /// Thrown if is null. /// @@ -67,12 +55,13 @@ public void Register(IBindingTypeConverter converter) ArgumentExceptionHelper.ThrowIfNull(converter); const int InitialConverterListCapacity = 4; + const int InitialRegistryCapacity = 16; var key = (converter.FromType, converter.ToType); lock (_gate) { - var snap = _snapshot ?? new Snapshot(new(16)); + var snap = _snapshot ?? new Snapshot(new(InitialRegistryCapacity)); // Copy-on-write update: clone the dictionary shallowly var newDict = CloneRegistryShallow(snap.ConvertersByTypePair); @@ -90,9 +79,7 @@ public void Register(IBindingTypeConverter converter) } } - /// - /// Attempts to retrieve the best converter for the specified type pair. - /// + /// Attempts to retrieve the best converter for the specified type pair. /// The source type to convert from. /// The target type to convert to. /// @@ -141,9 +128,7 @@ public void Register(IBindingTypeConverter converter) return best; } - /// - /// Returns all registered converters. - /// + /// Returns all registered converters. /// /// A sequence of all converters currently registered in the registry. /// Returns an empty sequence if no converters are registered. @@ -169,9 +154,7 @@ public IEnumerable GetAllConverters() return result; } - /// - /// Creates a shallow clone of the converter dictionary, preserving list references without deep-copying them. - /// + /// Creates a shallow clone of the converter dictionary, preserving list references without deep-copying them. /// The source dictionary to clone. /// A new dictionary with the same entries as . [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -189,9 +172,7 @@ public IEnumerable GetAllConverters() return clone; } - /// - /// Immutable snapshot of the registry state for lock-free reads. - /// + /// Immutable snapshot of the registry state for lock-free reads. /// The converters indexed by source and target type pair. private sealed record Snapshot( Dictionary<(Type fromType, Type toType), List> ConvertersByTypePair); diff --git a/src/ReactiveUI.Binding/Bindings/Converters/ConverterMigrationHelper.cs b/src/ReactiveUI.Binding/Bindings/Converters/ConverterMigrationHelper.cs index 34062d5..f7e7717 100644 --- a/src/ReactiveUI.Binding/Bindings/Converters/ConverterMigrationHelper.cs +++ b/src/ReactiveUI.Binding/Bindings/Converters/ConverterMigrationHelper.cs @@ -4,9 +4,7 @@ namespace ReactiveUI.Binding; -/// -/// Provides helper methods for migrating converters from Splat to the new . -/// +/// Provides helper methods for migrating converters from Splat to the new . /// /// /// This class assists with migrating from the legacy Splat-based converter registration @@ -24,9 +22,7 @@ namespace ReactiveUI.Binding; /// public static class ConverterMigrationHelper { - /// - /// Extracts all converters from a Splat dependency resolver. - /// + /// Extracts all converters from a Splat dependency resolver. /// The Splat resolver to extract converters from. Must not be null. /// /// A tuple containing lists of typed converters, fallback converters, and set-method converters. @@ -40,58 +36,33 @@ public static ( { ArgumentExceptionHelper.ThrowIfNull(resolver); - var typed = new List( - resolver.GetServices().Where(static c => c is not null)!); - - var fallback = new List( - resolver.GetServices().Where(static c => c is not null)!); - - var setMethod = new List( - resolver.GetServices().Where(static c => c is not null)!); - - return (typed, fallback, setMethod); - } - - /// - /// Imports converters from a Splat resolver directly into a . - /// - /// The converter service to import into. Must not be null. - /// The Splat resolver to import converters from. Must not be null. - /// - /// Thrown if or is null. - /// - /// - /// - /// This extension method extracts all converters from the Splat resolver and registers them - /// with the specified . - /// - /// - /// Important: This method imports converters at the time it's called. - /// Any converters registered with Splat after this call will not be included. - /// - /// - public static void ImportFrom( - this ConverterService converterService, - IReadonlyDependencyResolver resolver) - { - ArgumentExceptionHelper.ThrowIfNull(converterService); - ArgumentExceptionHelper.ThrowIfNull(resolver); - - var (typed, fallback, setMethod) = ExtractConverters(resolver); - - foreach (var converter in typed) + var typed = new List(); + foreach (var converter in resolver.GetServices()) { - converterService.TypedConverters.Register(converter); + if (converter is not null) + { + typed.Add(converter); + } } - foreach (var converter in fallback) + var fallback = new List(); + foreach (var converter in resolver.GetServices()) { - converterService.FallbackConverters.Register(converter); + if (converter is not null) + { + fallback.Add(converter); + } } - foreach (var converter in setMethod) + var setMethod = new List(); + foreach (var converter in resolver.GetServices()) { - converterService.SetMethodConverters.Register(converter); + if (converter is not null) + { + setMethod.Add(converter); + } } + + return (typed, fallback, setMethod); } } diff --git a/src/ReactiveUI.Binding/Bindings/Converters/ConverterMigrationHelperMixins.cs b/src/ReactiveUI.Binding/Bindings/Converters/ConverterMigrationHelperMixins.cs new file mode 100644 index 0000000..4ea3178 --- /dev/null +++ b/src/ReactiveUI.Binding/Bindings/Converters/ConverterMigrationHelperMixins.cs @@ -0,0 +1,62 @@ +// Copyright (c) 2019-2026 ReactiveUI Association Incorporated. All rights reserved. +// ReactiveUI Association Incorporated licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +namespace ReactiveUI.Binding; + +/// Service-scoped entry points for importing Splat-registered converters. +/// +/// +/// Example: Direct import into existing service +/// +/// +/// var converterService = BindingConverters.Current; +/// converterService.ImportFrom(Splat.Locator.Current); +/// +/// +public static class ConverterMigrationHelperMixins +{ + /// Provides ImportFrom extension members for . + /// The converter service to import into. Must not be null. + extension(ConverterService converterService) + { + /// Imports converters from a Splat resolver directly into a . + /// The Splat resolver to import converters from. Must not be null. + /// + /// Thrown if or is null. + /// + /// + /// + /// This extension method extracts all converters from the Splat resolver and registers them + /// with the specified . + /// + /// + /// Important: This method imports converters at the time it's called. + /// Any converters registered with Splat after this call will not be included. + /// + /// + public void ImportFrom( + IReadonlyDependencyResolver resolver) + { + ArgumentExceptionHelper.ThrowIfNull(converterService); + ArgumentExceptionHelper.ThrowIfNull(resolver); + + var (typed, fallback, setMethod) = ConverterMigrationHelper.ExtractConverters(resolver); + + foreach (var converter in typed) + { + converterService.TypedConverters.Register(converter); + } + + foreach (var converter in fallback) + { + converterService.FallbackConverters.Register(converter); + } + + foreach (var converter in setMethod) + { + converterService.SetMethodConverters.Register(converter); + } + } + } +} diff --git a/src/ReactiveUI.Binding/Bindings/Converters/ConverterService.cs b/src/ReactiveUI.Binding/Bindings/Converters/ConverterService.cs index 8862d1d..6369f8e 100644 --- a/src/ReactiveUI.Binding/Bindings/Converters/ConverterService.cs +++ b/src/ReactiveUI.Binding/Bindings/Converters/ConverterService.cs @@ -4,9 +4,7 @@ namespace ReactiveUI.Binding; -/// -/// Provides unified access to all converter registries in ReactiveUI.Binding. -/// +/// Provides unified access to all converter registries in ReactiveUI.Binding. /// /// /// This service manages three types of converters: @@ -44,9 +42,7 @@ namespace ReactiveUI.Binding; /// public sealed class ConverterService { - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. public ConverterService() { TypedConverters = new(); @@ -54,33 +50,25 @@ public ConverterService() SetMethodConverters = new(); } - /// - /// Gets the registry for typed binding converters. - /// + /// Gets the registry for typed binding converters. /// /// The typed converter registry for exact type-pair conversions. /// public BindingTypeConverterRegistry TypedConverters { get; } - /// - /// Gets the registry for fallback binding converters. - /// + /// Gets the registry for fallback binding converters. /// /// The fallback converter registry for runtime type conversions. /// public BindingFallbackConverterRegistry FallbackConverters { get; } - /// - /// Gets the registry for set-method binding converters. - /// + /// Gets the registry for set-method binding converters. /// /// The set-method converter registry for specialized set operations. /// public SetMethodBindingConverterRegistry SetMethodConverters { get; } - /// - /// Resolves the best converter for the specified type pair. - /// + /// Resolves the best converter for the specified type pair. /// The source type to convert from. /// The target type to convert to. /// @@ -90,13 +78,9 @@ public ConverterService() /// Thrown if or is null. /// public object? ResolveConverter( -#if NET [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] -#endif Type fromType, -#if NET [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] -#endif Type toType) { ArgumentExceptionHelper.ThrowIfNull(fromType); @@ -104,33 +88,18 @@ public ConverterService() // Phase 1: Try exact type-pair match (typed converters) var typed = TypedConverters.TryGetConverter(fromType, toType); - if (typed is not null) - { - return typed; - } - - // Phase 2: Try fallback converters (runtime type checking) - return FallbackConverters.TryGetConverter(fromType, toType); + return typed is not null ? typed : FallbackConverters.TryGetConverter(fromType, toType); } - /// - /// Resolves the best set-method converter for the specified type pair. - /// + /// Resolves the best set-method converter for the specified type pair. /// The source type to convert from. May be null. /// The target type to convert to. May be null. /// /// The best set-method converter for the type pair, or if no converter is available. /// public ISetMethodBindingConverter? ResolveSetMethodConverter( -#if NET [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] -#endif Type? fromType, -#if NET [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] -#endif - Type? toType) - { - return SetMethodConverters.TryGetConverter(fromType, toType); - } + Type? toType) => SetMethodConverters.TryGetConverter(fromType, toType); } diff --git a/src/ReactiveUI.Binding/Bindings/Converters/DefaultConverterRegistration.cs b/src/ReactiveUI.Binding/Bindings/Converters/DefaultConverterRegistration.cs index 0ff218a..99acce3 100644 --- a/src/ReactiveUI.Binding/Bindings/Converters/DefaultConverterRegistration.cs +++ b/src/ReactiveUI.Binding/Bindings/Converters/DefaultConverterRegistration.cs @@ -4,18 +4,14 @@ namespace ReactiveUI.Binding; -/// -/// Registers all built-in type converters with a . -/// +/// Registers all built-in type converters with a . /// /// This class is public to allow external packages (e.g., ReactiveUI) to register /// the default set of binding converters provided by ReactiveUI.Binding. /// public static class DefaultConverterRegistration { - /// - /// Registers all default built-in converters with the specified . - /// + /// Registers all default built-in converters with the specified . /// The converter service to register defaults into. /// /// Call this method during application initialization to populate the converter service @@ -27,12 +23,42 @@ public static void RegisterDefaults(ConverterService service) var registry = service.TypedConverters; + RegisterCoreConverters(registry); + RegisterNumericConverters(registry); + RegisterTemporalConverters(registry); + } + + /// Registers the identity, equality, boolean, guid and uri converters. + /// The registry to populate. + private static void RegisterCoreConverters(BindingTypeConverterRegistry registry) + { // String identity converter registry.Register(new StringConverter()); // Equality converter (last resort, affinity 1) registry.Register(new EqualityTypeConverter()); + // Boolean converters + registry.Register(new BooleanToStringTypeConverter()); + registry.Register(new StringToBooleanTypeConverter()); + registry.Register(new NullableBooleanToStringTypeConverter()); + registry.Register(new StringToNullableBooleanTypeConverter()); + + // Guid converters + registry.Register(new GuidToStringTypeConverter()); + registry.Register(new StringToGuidTypeConverter()); + registry.Register(new NullableGuidToStringTypeConverter()); + registry.Register(new StringToNullableGuidTypeConverter()); + + // Uri converters + registry.Register(new UriToStringTypeConverter()); + registry.Register(new StringToUriTypeConverter()); + } + + /// Registers the converters for the numeric primitives and their nullable forms. + /// The registry to populate. + private static void RegisterNumericConverters(BindingTypeConverterRegistry registry) + { // Integer converters registry.Register(new IntegerToStringTypeConverter()); registry.Register(new StringToIntegerTypeConverter()); @@ -88,13 +114,12 @@ public static void RegisterDefaults(ConverterService service) registry.Register(new ByteToNullableByteTypeConverter()); registry.Register(new NullableByteToStringTypeConverter()); registry.Register(new StringToNullableByteTypeConverter()); + } - // Boolean converters - registry.Register(new BooleanToStringTypeConverter()); - registry.Register(new StringToBooleanTypeConverter()); - registry.Register(new NullableBooleanToStringTypeConverter()); - registry.Register(new StringToNullableBooleanTypeConverter()); - + /// Registers the date, time and duration converters. + /// The registry to populate. + private static void RegisterTemporalConverters(BindingTypeConverterRegistry registry) + { // DateTime converters registry.Register(new DateTimeToStringTypeConverter()); registry.Register(new StringToDateTimeTypeConverter()); @@ -113,16 +138,6 @@ public static void RegisterDefaults(ConverterService service) registry.Register(new NullableTimeSpanToStringTypeConverter()); registry.Register(new StringToNullableTimeSpanTypeConverter()); - // Guid converters - registry.Register(new GuidToStringTypeConverter()); - registry.Register(new StringToGuidTypeConverter()); - registry.Register(new NullableGuidToStringTypeConverter()); - registry.Register(new StringToNullableGuidTypeConverter()); - - // Uri converters - registry.Register(new UriToStringTypeConverter()); - registry.Register(new StringToUriTypeConverter()); - #if NET8_0_OR_GREATER // DateOnly converters (NET8+ only) registry.Register(new DateOnlyToStringTypeConverter()); diff --git a/src/ReactiveUI.Binding/Bindings/Converters/SetMethodBindingConverterRegistry.cs b/src/ReactiveUI.Binding/Bindings/Converters/SetMethodBindingConverterRegistry.cs index fc1f2d4..3238555 100644 --- a/src/ReactiveUI.Binding/Bindings/Converters/SetMethodBindingConverterRegistry.cs +++ b/src/ReactiveUI.Binding/Bindings/Converters/SetMethodBindingConverterRegistry.cs @@ -4,9 +4,7 @@ namespace ReactiveUI.Binding; -/// -/// Thread-safe registry for set-method binding converters using a lock-free snapshot pattern. -/// +/// Thread-safe registry for set-method binding converters using a lock-free snapshot pattern. /// /// /// This registry uses a copy-on-write snapshot pattern optimized for read-heavy workloads: @@ -34,32 +32,24 @@ namespace ReactiveUI.Binding; /// public sealed class SetMethodBindingConverterRegistry { - /// - /// Synchronization gate for serializing write operations. - /// -#if NET9_0_OR_GREATER + /// Synchronization gate for serializing write operations. private readonly Lock _gate = new(); -#else - private readonly object _gate = new(); -#endif - /// - /// The current immutable snapshot of registered set-method converters, read via volatile access. - /// + /// The current immutable snapshot of registered set-method converters, read via volatile access. private Snapshot? _snapshot; - /// - /// Registers a set-method binding converter. - /// + /// Registers a set-method binding converter. /// The converter to register. Must not be null. /// Thrown if is null. public void Register(ISetMethodBindingConverter converter) { ArgumentExceptionHelper.ThrowIfNull(converter); + const int InitialRegistryCapacity = 8; + lock (_gate) { - var snap = _snapshot ?? new Snapshot(new(8)); + var snap = _snapshot ?? new Snapshot(new(InitialRegistryCapacity)); // Copy-on-write update: clone the list var newList = new List(snap.Converters) { converter }; @@ -69,22 +59,16 @@ public void Register(ISetMethodBindingConverter converter) } } - /// - /// Attempts to retrieve the best set-method converter for the specified type pair. - /// + /// Attempts to retrieve the best set-method converter for the specified type pair. /// The source type to convert from. May be null. /// The target type to convert to. May be null. /// /// The converter with the highest affinity for the type pair, or if no converter supports the conversion. /// public ISetMethodBindingConverter? TryGetConverter( -#if NET [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] -#endif Type? fromType, -#if NET [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] -#endif Type? toType) { var snap = Volatile.Read(ref _snapshot); @@ -112,9 +96,7 @@ public void Register(ISetMethodBindingConverter converter) return best; } - /// - /// Returns all registered set-method converters. - /// + /// Returns all registered set-method converters. /// /// A sequence of all set-method converters currently registered in the registry. /// Returns an empty sequence if no converters are registered. @@ -122,17 +104,10 @@ public void Register(ISetMethodBindingConverter converter) public IEnumerable GetAllConverters() { var snap = Volatile.Read(ref _snapshot); - if (snap is null) - { - return []; - } - - return [.. snap.Converters]; + return snap is null ? [] : [.. snap.Converters]; } - /// - /// Immutable snapshot of the registry state for lock-free reads. - /// + /// Immutable snapshot of the registry state for lock-free reads. /// The registered set-method converters. private sealed record Snapshot(List Converters); } diff --git a/src/ReactiveUI.Binding/Bindings/IBindingFallbackConverter.cs b/src/ReactiveUI.Binding/Bindings/IBindingFallbackConverter.cs index 9416beb..3dad78c 100644 --- a/src/ReactiveUI.Binding/Bindings/IBindingFallbackConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/IBindingFallbackConverter.cs @@ -34,9 +34,7 @@ namespace ReactiveUI.Binding; /// public interface IBindingFallbackConverter : IEnableLogger { - /// - /// Calculates affinity for the specified runtime type pair. - /// + /// Calculates affinity for the specified runtime type pair. /// The runtime source type. /// The target type. /// @@ -58,18 +56,12 @@ public interface IBindingFallbackConverter : IEnableLogger /// /// int GetAffinityForObjects( -#if NET [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] -#endif Type fromType, -#if NET [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] -#endif Type toType); - /// - /// Attempts to convert the value to the target type. - /// + /// Attempts to convert the value to the target type. /// The runtime source type (guaranteed non-null). /// The value to convert (guaranteed non-null). /// The target type (guaranteed non-null). @@ -89,14 +81,10 @@ int GetAffinityForObjects( /// /// bool TryConvert( -#if NET [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] -#endif Type fromType, object from, -#if NET [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] -#endif Type toType, object? conversionHint, [NotNullWhen(true)] out object? result); diff --git a/src/ReactiveUI.Binding/Bindings/IBindingTypeConverter.cs b/src/ReactiveUI.Binding/Bindings/IBindingTypeConverter.cs index a83fa55..dfb9aef 100644 --- a/src/ReactiveUI.Binding/Bindings/IBindingTypeConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/IBindingTypeConverter.cs @@ -11,14 +11,10 @@ namespace ReactiveUI.Binding; /// public interface IBindingTypeConverter : IEnableLogger { - /// - /// Gets the source type supported by this converter. - /// + /// Gets the source type supported by this converter. Type FromType { get; } - /// - /// Gets the target type supported by this converter. - /// + /// Gets the target type supported by this converter. Type ToType { get; } /// @@ -32,9 +28,7 @@ public interface IBindingTypeConverter : IEnableLogger /// zero or a negative value otherwise. int GetAffinityForObjects(); - /// - /// Attempts to convert using the typed implementation, exposed via an object-based shim. - /// + /// Attempts to convert using the typed implementation, exposed via an object-based shim. /// The source value. /// Implementation-defined hint. /// The converted value. diff --git a/src/ReactiveUI.Binding/Bindings/IBindingTypeConverter{TFrom,TTo}.cs b/src/ReactiveUI.Binding/Bindings/IBindingTypeConverter{TFrom,TTo}.cs index 03402a2..703c72c 100644 --- a/src/ReactiveUI.Binding/Bindings/IBindingTypeConverter{TFrom,TTo}.cs +++ b/src/ReactiveUI.Binding/Bindings/IBindingTypeConverter{TFrom,TTo}.cs @@ -4,10 +4,7 @@ namespace ReactiveUI.Binding; -/// -/// Generic type-safe interface for converting between specific types. -/// Implement this alongside for AOT-safe conversions. -/// +/// Generic type-safe interface for converting between specific types. Implement this alongside for AOT-safe conversions. /// The source type to convert from. /// The target type to convert to. /// @@ -23,9 +20,7 @@ namespace ReactiveUI.Binding; /// public interface IBindingTypeConverter : IBindingTypeConverter { - /// - /// Convert a value to the target type in a type-safe manner. - /// + /// Convert a value to the target type in a type-safe manner. /// The value to convert. /// Implementation-defined hint for conversion (e.g., format string, locale). /// The converted value. May be when conversion succeeds for nullable targets. diff --git a/src/ReactiveUI.Binding/Bindings/ISetMethodBindingConverter.cs b/src/ReactiveUI.Binding/Bindings/ISetMethodBindingConverter.cs index 1593d51..c0a1ef5 100644 --- a/src/ReactiveUI.Binding/Bindings/ISetMethodBindingConverter.cs +++ b/src/ReactiveUI.Binding/Bindings/ISetMethodBindingConverter.cs @@ -4,9 +4,7 @@ namespace ReactiveUI.Binding; -/// -/// This converter will allow users to change the way the set functionality is performed in ReactiveUI property binding. -/// +/// This converter will allow users to change the way the set functionality is performed in ReactiveUI property binding. public interface ISetMethodBindingConverter : IEnableLogger { /// @@ -22,9 +20,7 @@ public interface ISetMethodBindingConverter : IEnableLogger /// zero or a negative value otherwise. int GetAffinityForObjects(Type? fromType, Type? toType); - /// - /// Convert a given object to the specified type. - /// + /// Convert a given object to the specified type. /// The target object we are setting to. /// The value to set on the new object. /// The arguments required. Used for indexer based values. diff --git a/src/ReactiveUI.Binding/Bindings/ReactiveBinding.cs b/src/ReactiveUI.Binding/Bindings/ReactiveBinding.cs index 35cac63..2b8f154 100644 --- a/src/ReactiveUI.Binding/Bindings/ReactiveBinding.cs +++ b/src/ReactiveUI.Binding/Bindings/ReactiveBinding.cs @@ -4,27 +4,19 @@ namespace ReactiveUI.Binding; -/// -/// Default implementation of used by generated view-first bindings. -/// +/// Default implementation of used by generated view-first bindings. /// The type of the view. /// The type of the bound value. public sealed class ReactiveBinding : IReactiveBinding where TView : IViewFor { - /// - /// The underlying subscription that is disposed when this binding is disposed. - /// + /// The underlying subscription that is disposed when this binding is disposed. private readonly IDisposable _subscription; - /// - /// Tracks whether this instance has been disposed (0 = not disposed, 1 = disposed). - /// + /// Tracks whether this instance has been disposed (0 = not disposed, 1 = disposed). private int _disposed; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The view that is bound. /// An observable that signals when the binding value changes. /// The direction of the binding. @@ -67,9 +59,7 @@ public void Dispose() _subscription.Dispose(); } - /// - /// Atomically marks this instance as disposed. - /// + /// Atomically marks this instance as disposed. /// if this is the first disposal; otherwise . [ExcludeFromCodeCoverage] [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ReactiveUI.Binding/Builder/IReactiveUIBindingBuilder.cs b/src/ReactiveUI.Binding/Builder/IReactiveUIBindingBuilder.cs index c9397e5..dd4ab6f 100644 --- a/src/ReactiveUI.Binding/Builder/IReactiveUIBindingBuilder.cs +++ b/src/ReactiveUI.Binding/Builder/IReactiveUIBindingBuilder.cs @@ -28,61 +28,44 @@ public interface IReactiveUIBindingBuilder : IAppBuilder /// The builder instance for chaining. new IReactiveUIBindingBuilder WithCoreServices(); - /// - /// Registers a platform-specific module with the builder. - /// + /// Registers a platform-specific module with the builder. /// The type of the platform module. Must implement . /// The platform module instance to register. /// The builder instance for chaining. IReactiveUIBindingBuilder WithPlatformModule(T module) where T : IModule; - /// - /// Registers a custom action to be executed during the build phase. - /// + /// Registers a custom action to be executed during the build phase. /// An action that receives the mutable dependency resolver. /// The builder instance for chaining. IReactiveUIBindingBuilder WithRegistration(Action configureAction); - /// - /// Registers a typed binding converter. - /// + /// Registers a typed binding converter. /// The converter instance to register. /// The builder instance for chaining. IReactiveUIBindingBuilder WithConverter(IBindingTypeConverter converter); - /// - /// Registers a fallback binding converter. - /// + /// Registers a fallback binding converter. /// The fallback converter instance to register. /// The builder instance for chaining. IReactiveUIBindingBuilder WithFallbackConverter(IBindingFallbackConverter converter); - /// - /// Registers a set-method binding converter. - /// + /// Registers a set-method binding converter. /// The set-method converter instance to register. /// The builder instance for chaining. IReactiveUIBindingBuilder WithSetMethodConverter(ISetMethodBindingConverter converter); - /// - /// Registers a custom command binder for binding - /// instances to UI controls. - /// + /// Registers a custom command binder for binding instances to UI controls. /// The command binder instance to register. /// The builder instance for chaining. IReactiveUIBindingBuilder WithCommandBinder(ICreatesCommandBinding binder); - /// - /// Configures the default view locator with explicit view-to-view-model mappings. - /// + /// Configures the default view locator with explicit view-to-view-model mappings. /// An action that receives a for registering mappings. /// The builder instance for chaining. IReactiveUIBindingBuilder ConfigureViewLocator(Action configure); - /// - /// Builds the application and returns the configured instance. - /// + /// Builds the application and returns the configured instance. /// The configured application instance. IReactiveUIBindingInstance BuildApp(); } diff --git a/src/ReactiveUI.Binding/Builder/IReactiveUIBindingInstance.cs b/src/ReactiveUI.Binding/Builder/IReactiveUIBindingInstance.cs index 0dcf5f5..f529090 100644 --- a/src/ReactiveUI.Binding/Builder/IReactiveUIBindingInstance.cs +++ b/src/ReactiveUI.Binding/Builder/IReactiveUIBindingInstance.cs @@ -6,8 +6,6 @@ namespace ReactiveUI.Binding.Builder; -/// -/// Represents a configured ReactiveUI.Binding application instance. -/// +/// Represents a configured ReactiveUI.Binding application instance. /// public interface IReactiveUIBindingInstance : IAppInstance; diff --git a/src/ReactiveUI.Binding/Builder/ReactiveUIBindingBuilder.cs b/src/ReactiveUI.Binding/Builder/ReactiveUIBindingBuilder.cs index 3b4ba6f..d1e5f70 100644 --- a/src/ReactiveUI.Binding/Builder/ReactiveUIBindingBuilder.cs +++ b/src/ReactiveUI.Binding/Builder/ReactiveUIBindingBuilder.cs @@ -26,14 +26,10 @@ namespace ReactiveUI.Binding.Builder; /// public sealed class ReactiveUIBindingBuilder : AppBuilder, IReactiveUIBindingBuilder, IReactiveUIBindingInstance { - /// - /// Tracks whether core services have already been registered to prevent duplicate registration. - /// + /// Tracks whether core services have already been registered to prevent duplicate registration. private bool _coreRegistered; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The dependency resolver to configure. /// The configured services. public ReactiveUIBindingBuilder(IMutableDependencyResolver resolver, IReadonlyDependencyResolver? current) @@ -45,9 +41,7 @@ public ReactiveUIBindingBuilder(IMutableDependencyResolver resolver, IReadonlyDe CurrentMutable.RegisterConstant(() => ConverterService); } - /// - /// Gets the converter service used for binding type conversions. - /// + /// Gets the converter service used for binding type conversions. /// /// This service provides access to three specialized registries: /// @@ -59,9 +53,7 @@ public ReactiveUIBindingBuilder(IMutableDependencyResolver resolver, IReadonlyDe /// public ConverterService ConverterService { get; } = new(); - /// - /// Registers a platform-specific module with the builder. - /// + /// Registers a platform-specific module with the builder. /// The type of the platform module. Must implement . /// The platform module instance to register. /// The builder instance for chaining. @@ -69,13 +61,11 @@ public IReactiveUIBindingBuilder WithPlatformModule(T module) where T : IModule { ArgumentExceptionHelper.ThrowIfNull(module); - UsingModule(module); + _ = UsingModule(module); return this; } - /// - /// Adds a custom registration action to be executed during the build phase. - /// + /// Adds a custom registration action to be executed during the build phase. /// An action that receives the mutable dependency resolver. /// The builder instance for chaining. public IReactiveUIBindingBuilder WithRegistration(Action configureAction) @@ -85,9 +75,7 @@ public IReactiveUIBindingBuilder WithRegistration(Action - /// Registers a typed binding converter. - /// + /// Registers a typed binding converter. /// The converter instance to register. /// The builder instance for chaining. public IReactiveUIBindingBuilder WithConverter(IBindingTypeConverter converter) @@ -97,9 +85,7 @@ public IReactiveUIBindingBuilder WithConverter(IBindingTypeConverter converter) return this; } - /// - /// Registers a fallback binding converter. - /// + /// Registers a fallback binding converter. /// The fallback converter instance to register. /// The builder instance for chaining. public IReactiveUIBindingBuilder WithFallbackConverter(IBindingFallbackConverter converter) @@ -109,9 +95,7 @@ public IReactiveUIBindingBuilder WithFallbackConverter(IBindingFallbackConverter return this; } - /// - /// Registers a set-method binding converter. - /// + /// Registers a set-method binding converter. /// The set-method converter instance to register. /// The builder instance for chaining. public IReactiveUIBindingBuilder WithSetMethodConverter(ISetMethodBindingConverter converter) @@ -121,9 +105,7 @@ public IReactiveUIBindingBuilder WithSetMethodConverter(ISetMethodBindingConvert return this; } - /// - /// Registers a custom command binder for binding commands to UI controls. - /// + /// Registers a custom command binder for binding commands to UI controls. /// The command binder instance to register. /// The builder instance for chaining. public IReactiveUIBindingBuilder WithCommandBinder(ICreatesCommandBinding binder) @@ -133,9 +115,7 @@ public IReactiveUIBindingBuilder WithCommandBinder(ICreatesCommandBinding binder return this; } - /// - /// Configures the default view locator with explicit view-to-view-model mappings. - /// + /// Configures the default view locator with explicit view-to-view-model mappings. /// An action that receives a for registering mappings. /// The builder instance for chaining. public IReactiveUIBindingBuilder ConfigureViewLocator(Action configure) @@ -149,9 +129,7 @@ public IReactiveUIBindingBuilder ConfigureViewLocator(Action return this; } - /// - /// Registers the core ReactiveUI.Binding services in an AOT-compatible manner. - /// + /// Registers the core ReactiveUI.Binding services in an AOT-compatible manner. /// The builder instance for chaining. public override IAppBuilder WithCoreServices() { @@ -161,10 +139,10 @@ public override IAppBuilder WithCoreServices() DefaultConverterRegistration.RegisterDefaults(ConverterService); // Register core observation services - WithPlatformModule(new ReactiveUIBindingModule()); + _ = WithPlatformModule(new ReactiveUIBindingModule()); // Register default view locator - CurrentMutable.RegisterLazySingleton(() => new DefaultViewLocator()); + CurrentMutable.RegisterLazySingleton(static () => new DefaultViewLocator()); _coreRegistered = true; } @@ -176,9 +154,7 @@ public override IAppBuilder WithCoreServices() IReactiveUIBindingBuilder IReactiveUIBindingBuilder.WithCoreServices() => (IReactiveUIBindingBuilder)WithCoreServices(); - /// - /// Builds the application and returns the configured instance. - /// + /// Builds the application and returns the configured instance. /// The configured application instance. /// Thrown if building the app instance fails. public IReactiveUIBindingInstance BuildApp() diff --git a/src/ReactiveUI.Binding/Builder/ReactiveUIBindingModule.cs b/src/ReactiveUI.Binding/Builder/ReactiveUIBindingModule.cs index f3394df..5f2e986 100644 --- a/src/ReactiveUI.Binding/Builder/ReactiveUIBindingModule.cs +++ b/src/ReactiveUI.Binding/Builder/ReactiveUIBindingModule.cs @@ -7,9 +7,7 @@ namespace ReactiveUI.Binding.Builder; -/// -/// Core module that registers the default ReactiveUI.Binding services with the dependency resolver. -/// +/// Core module that registers the default ReactiveUI.Binding services with the dependency resolver. /// /// This module registers: /// @@ -29,7 +27,7 @@ public void Configure(IMutableDependencyResolver resolver) ArgumentExceptionHelper.ThrowIfNull(resolver); // Register core ICreatesObservableForProperty implementations - resolver.RegisterLazySingleton(() => new INPCObservableForProperty()); - resolver.RegisterLazySingleton(() => new POCOObservableForProperty()); + resolver.RegisterLazySingleton(static () => new INPCObservableForProperty()); + resolver.RegisterLazySingleton(static () => new POCOObservableForProperty()); } } diff --git a/src/ReactiveUI.Binding/Builder/RxBindingBuilder.cs b/src/ReactiveUI.Binding/Builder/RxBindingBuilder.cs index 56fbec6..1ad3e7a 100644 --- a/src/ReactiveUI.Binding/Builder/RxBindingBuilder.cs +++ b/src/ReactiveUI.Binding/Builder/RxBindingBuilder.cs @@ -6,9 +6,7 @@ namespace ReactiveUI.Binding.Builder; -/// -/// Static factory for creating instances. -/// +/// Static factory for creating instances. /// /// /// RxBindingBuilder.CreateReactiveUIBindingBuilder() @@ -18,43 +16,18 @@ namespace ReactiveUI.Binding.Builder; /// public static class RxBindingBuilder { - /// - /// Synchronization gate for initialization and reset operations. - /// -#if NET9_0_OR_GREATER + /// Synchronization gate for initialization and reset operations. private static readonly Lock _resetLock = new(); -#else - private static readonly object _resetLock = new(); -#endif - /// - /// Tracks whether ReactiveUI.Binding has been initialized (0 = not initialized, 1 = initialized). - /// + /// Tracks whether ReactiveUI.Binding has been initialized (0 = not initialized, 1 = initialized). private static int _hasBeenInitialized; // 0 = false, 1 = true - /// - /// Creates a new using the current Splat locator. - /// + /// Creates a new using the current Splat locator. /// A new builder instance. public static ReactiveUIBindingBuilder CreateReactiveUIBindingBuilder() => new(AppLocator.CurrentMutable, AppLocator.Current); - /// - /// Creates a new using the specified dependency resolver. - /// - /// The dependency resolver to use. - /// A new builder instance. - public static ReactiveUIBindingBuilder CreateReactiveUIBindingBuilder(this IMutableDependencyResolver resolver) - { - ArgumentExceptionHelper.ThrowIfNull(resolver); - - var readonlyResolver = resolver as IReadonlyDependencyResolver ?? AppLocator.Current; - return new(resolver, readonlyResolver); - } - - /// - /// Ensures ReactiveUI.Binding has been initialized via the builder pattern. - /// + /// Ensures ReactiveUI.Binding has been initialized via the builder pattern. /// Thrown if BuildApp() has not been called. public static void EnsureInitialized() { @@ -63,18 +36,16 @@ public static void EnsureInitialized() if (_hasBeenInitialized == 0) { throw new InvalidOperationException( - "ReactiveUI.Binding has not been initialized. You must initialize using the builder pattern.\n\n" + - "Example:\n" + - "RxBindingBuilder.CreateReactiveUIBindingBuilder()\n" + - " .WithCoreServices()\n" + - " .BuildApp();"); + "ReactiveUI.Binding has not been initialized. You must initialize using the builder pattern.\n\n" + + "Example:\n" + + "RxBindingBuilder.CreateReactiveUIBindingBuilder()\n" + + " .WithCoreServices()\n" + + " .BuildApp();"); } } } - /// - /// Resets the initialization state for testing purposes only. - /// + /// Resets the initialization state for testing purposes only. /// /// WARNING: This method should ONLY be used in unit tests. Never call in production code. /// @@ -88,9 +59,7 @@ internal static void ResetForTesting() } } - /// - /// Marks ReactiveUI.Binding as initialized. Called by . - /// + /// Marks ReactiveUI.Binding as initialized. Called by . internal static void MarkAsInitialized() { lock (_resetLock) diff --git a/src/ReactiveUI.Binding/Builder/RxBindingBuilderMixins.cs b/src/ReactiveUI.Binding/Builder/RxBindingBuilderMixins.cs new file mode 100644 index 0000000..1fb14f1 --- /dev/null +++ b/src/ReactiveUI.Binding/Builder/RxBindingBuilderMixins.cs @@ -0,0 +1,24 @@ +// Copyright (c) 2019-2026 ReactiveUI Association Incorporated. All rights reserved. +// ReactiveUI Association Incorporated licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +namespace ReactiveUI.Binding.Builder; + +/// Resolver-scoped entry points for creating instances. +public static class RxBindingBuilderMixins +{ + /// Provides CreateReactiveUIBindingBuilder extension members for . + /// The dependency resolver to use. + extension(IMutableDependencyResolver resolver) + { + /// Creates a new using the specified dependency resolver. + /// A new builder instance. + public ReactiveUIBindingBuilder CreateReactiveUIBindingBuilder() + { + ArgumentExceptionHelper.ThrowIfNull(resolver); + + var readonlyResolver = resolver as IReadonlyDependencyResolver ?? AppLocator.Current; + return new(resolver, readonlyResolver); + } + } +} diff --git a/src/ReactiveUI.Binding/CommandBinding/CommandBinderService.cs b/src/ReactiveUI.Binding/CommandBinding/CommandBinderService.cs index 48f308e..ee314f5 100644 --- a/src/ReactiveUI.Binding/CommandBinding/CommandBinderService.cs +++ b/src/ReactiveUI.Binding/CommandBinding/CommandBinderService.cs @@ -12,21 +12,16 @@ namespace ReactiveUI.Binding.CommandBinding; /// property observation via . /// [EditorBrowsable(EditorBrowsableState.Never)] -[SuppressMessage( - "Major Code Smell", - "S4018:Generic methods should provide type parameter for type inference", - Justification = "The type parameter denotes the target type (value/control/view), supplied explicitly by callers; it is not derivable from the arguments. Public API.")] public static class CommandBinderService { - /// - /// Gets the highest-affinity registered for the specified control type. - /// + /// Gets the highest-affinity registered for the specified control type. /// The type of the control. /// Whether the caller specifies a custom event target. /// The best binder, or if no registered binder supports the control type. + [SuppressMessage("Design", "SST2307:Type parameters should be inferable", Justification = "Specified explicitly by the caller; the interface shape dictates it.")] public static ICreatesCommandBinding? GetBinder< - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents | - DynamicallyAccessedMemberTypes.PublicProperties)] + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents + | DynamicallyAccessedMemberTypes.PublicProperties)] T>(bool hasEventTarget) { var resolver = Locator.Current; diff --git a/src/ReactiveUI.Binding/Expression/ExpressionMixins.cs b/src/ReactiveUI.Binding/Expression/ExpressionMixins.cs index d1636b1..03efa41 100644 --- a/src/ReactiveUI.Binding/Expression/ExpressionMixins.cs +++ b/src/ReactiveUI.Binding/Expression/ExpressionMixins.cs @@ -7,145 +7,156 @@ namespace ReactiveUI.Binding.Expressions; -/// -/// Extension methods associated with the Expression class. -/// +/// Extension methods associated with the Expression class. public static class ExpressionMixins { - /// - /// Gets all the chain of child expressions within an Expression. - /// Handles property member accesses, objects and indexes. - /// + /// Provides GetExpressionChain extension members for . /// The expression. - /// An enumerable of expressions. - public static IEnumerable GetExpressionChain(this Expression expression) + extension(Expression expression) { - var expressions = new List(); - var node = expression; + /// Gets all the chain of child expressions within an Expression. Handles property member accesses, objects and indexes. + /// An enumerable of expressions. + public IEnumerable GetExpressionChain() + { + var expressions = new List(); + var node = expression; + + while (node is not null && node.NodeType != ExpressionType.Parameter) + { + if (node is IndexExpression indexExpression) + { + expressions.Add(RebaseOnParameter(indexExpression)); + node = indexExpression.Object; + } + else if (node is MemberExpression memberExpression) + { + expressions.Add(RebaseOnParameter(memberExpression)); + node = memberExpression.Expression; + } + else + { + throw CreateUnsupportedExpressionException(node); + } + } - while (node is not null && node.NodeType != ExpressionType.Parameter) + expressions.Reverse(); + return expressions; + } + + /// + /// Gets the MemberInfo where an Expression is pointing towards. + /// Can handle MemberAccess and Index types and will handle + /// going through the Conversion Expressions. + /// + /// The member info from the expression. + public MemberInfo? GetMemberInfo() { - switch (node.NodeType) + while (true) { - case ExpressionType.Index when node is IndexExpression indexExpression: - { - var parent = indexExpression.GetParent(); - expressions.Add( - indexExpression.Object is not null && parent is not null && - indexExpression.Object.NodeType != ExpressionType.Parameter - ? indexExpression.Update(Expression.Parameter(parent.Type), indexExpression.Arguments) - : indexExpression); - - node = indexExpression.Object; - break; - } - - case ExpressionType.MemberAccess when node is MemberExpression memberExpression: - { - var parent = memberExpression.GetParent(); - expressions.Add( - parent is not null && memberExpression.Expression is not null && - memberExpression.Expression.NodeType != ExpressionType.Parameter - ? memberExpression.Update(Expression.Parameter(parent.Type)) - : memberExpression); - - node = memberExpression.Expression; - break; - } - - default: - { - var errorMessageBuilder = - new StringBuilder($"Unsupported expression of type '{node.NodeType}'."); - - if (node is ConstantExpression) + ArgumentExceptionHelper.ThrowIfNull(expression); + + MemberInfo? info; + switch (expression.NodeType) + { + case ExpressionType.Index when expression is IndexExpression indexExpression: { - errorMessageBuilder.Append(" Did you miss the member access prefix in the expression?"); + info = indexExpression.Indexer; + break; } - throw new NotSupportedException(errorMessageBuilder.ToString()); - } + case ExpressionType.MemberAccess when expression is MemberExpression memberExpression: + { + info = memberExpression.Member; + break; + } + + case ExpressionType.Convert or ExpressionType.ConvertChecked when expression is UnaryExpression unaryExpression: + { + expression = unaryExpression.Operand; + continue; + } + + default: + throw new NotSupportedException($"Unsupported {nameof(expression)} type: '{expression.NodeType}'"); + } + + return info; } } - expressions.Reverse(); - return expressions; - } + /// Gets the parent Expression of the current Expression object. + /// The parent expression. + public Expression? GetParent() + { + ArgumentExceptionHelper.ThrowIfNull(expression); - /// - /// Gets the MemberInfo where an Expression is pointing towards. - /// Can handle MemberAccess and Index types and will handle - /// going through the Conversion Expressions. - /// - /// The expression. - /// The member info from the expression. - public static MemberInfo? GetMemberInfo(this Expression expression) - { - while (true) + return expression.NodeType switch + { + ExpressionType.Index when expression is IndexExpression indexExpression => indexExpression.Object, + ExpressionType.MemberAccess when expression is MemberExpression memberExpression => memberExpression + .Expression, + _ => throw new NotSupportedException($"Unsupported expression type: '{expression.NodeType}'") + }; + } + + /// For an Expression which is an Index type, will get all the arguments passed to the indexer. + /// An array of arguments. + public object?[]? GetArgumentsArray() { ArgumentExceptionHelper.ThrowIfNull(expression); - MemberInfo? info; - switch (expression.NodeType) + if (expression.NodeType != ExpressionType.Index) { - case ExpressionType.Index when expression is IndexExpression indexExpression: - { - info = indexExpression.Indexer; - break; - } - - case ExpressionType.MemberAccess when expression is MemberExpression memberExpression: - { - info = memberExpression.Member; - break; - } - - case ExpressionType.Convert or ExpressionType.ConvertChecked when expression is UnaryExpression unaryExpression: - { - expression = unaryExpression.Operand; - continue; - } - - default: - throw new NotSupportedException($"Unsupported {nameof(expression)} type: '{expression.NodeType}'"); + return null; } - return info; + var arguments = ((IndexExpression)expression).Arguments; + var values = new object?[arguments.Count]; + for (var i = 0; i < arguments.Count; i++) + { + values[i] = ((ConstantExpression)arguments[i]).Value; + } + + return values; } } - /// - /// Gets the parent Expression of the current Expression object. - /// - /// The expression. - /// The parent expression. - public static Expression? GetParent(this Expression expression) + /// Rewrites an indexer access so it hangs off a parameter of the parent's type. + /// The indexer access to rebase. + /// The rebased expression, or the original when it already sits on a parameter. + private static IndexExpression RebaseOnParameter(IndexExpression indexExpression) { - ArgumentExceptionHelper.ThrowIfNull(expression); + var parent = indexExpression.GetParent(); + return indexExpression.Object is not null && parent is not null + && indexExpression.Object.NodeType != ExpressionType.Parameter + ? indexExpression.Update(Expression.Parameter(parent.Type), indexExpression.Arguments) + : indexExpression; + } - return expression.NodeType switch - { - ExpressionType.Index when expression is IndexExpression indexExpression => indexExpression.Object, - ExpressionType.MemberAccess when expression is MemberExpression memberExpression => memberExpression - .Expression, - _ => throw new NotSupportedException($"Unsupported expression type: '{expression.NodeType}'") - }; + /// Rewrites a member access so it hangs off a parameter of the parent's type. + /// The member access to rebase. + /// The rebased expression, or the original when it already sits on a parameter. + private static MemberExpression RebaseOnParameter(MemberExpression memberExpression) + { + var parent = memberExpression.GetParent(); + return parent is not null && memberExpression.Expression is not null + && memberExpression.Expression.NodeType != ExpressionType.Parameter + ? memberExpression.Update(Expression.Parameter(parent.Type)) + : memberExpression; } - /// - /// For an Expression which is an Index type, will get all the arguments passed to the indexer. - /// - /// The expression. - /// An array of arguments. - public static object?[]? GetArgumentsArray(this Expression expression) + /// Builds the exception thrown for an expression node the chain walker cannot decompose. + /// The unsupported node. + /// The exception to throw. + private static NotSupportedException CreateUnsupportedExpressionException(Expression node) { - ArgumentExceptionHelper.ThrowIfNull(expression); + var errorMessageBuilder = new StringBuilder($"Unsupported expression of type '{node.NodeType}'."); - if (expression.NodeType != ExpressionType.Index) + if (node is ConstantExpression) { - return null; + _ = errorMessageBuilder.Append(" Did you miss the member access prefix in the expression?"); } - return [.. ((IndexExpression)expression).Arguments.Cast().Select(static c => c.Value)]; + return new(errorMessageBuilder.ToString()); } } diff --git a/src/ReactiveUI.Binding/Expression/ExpressionRewriter.cs b/src/ReactiveUI.Binding/Expression/ExpressionRewriter.cs index 0acfe0c..f013fbf 100644 --- a/src/ReactiveUI.Binding/Expression/ExpressionRewriter.cs +++ b/src/ReactiveUI.Binding/Expression/ExpressionRewriter.cs @@ -37,26 +37,25 @@ public override Expression Visit(Expression? node) return node!.NodeType switch { ExpressionType.ArrayIndex => VisitBinary((BinaryExpression)node), - ExpressionType.ArrayLength => VisitUnary((UnaryExpression)node), + ExpressionType.ArrayLength or ExpressionType.Convert => VisitUnary((UnaryExpression)node), ExpressionType.Call => VisitMethodCall((MethodCallExpression)node), ExpressionType.Index => VisitIndex((IndexExpression)node), ExpressionType.MemberAccess => VisitMember((MemberExpression)node), ExpressionType.Parameter => VisitParameter((ParameterExpression)node), ExpressionType.Constant => VisitConstant((ConstantExpression)node), - ExpressionType.Convert => VisitUnary((UnaryExpression)node), _ => throw CreateUnsupportedNodeException(node) }; } - /// - /// Creates an exception for an unsupported expression node type, with an actionable error message. - /// + /// Creates an exception for an unsupported expression node type, with an actionable error message. /// The unsupported expression node. /// A describing the unsupported node. internal static Exception CreateUnsupportedNodeException(Expression node) { - var sb = new StringBuilder(96); - sb.Append("Unsupported expression of type '") + const int MessageBuilderCapacity = 96; + + var sb = new StringBuilder(MessageBuilderCapacity); + _ = sb.Append("Unsupported expression of type '") .Append(node.NodeType) .Append("' ") .Append(node) @@ -64,7 +63,7 @@ internal static Exception CreateUnsupportedNodeException(Expression node) if (node is BinaryExpression be) { - sb.Append(" Did you meant to use expressions '") + _ = sb.Append(" Did you meant to use expressions '") .Append(be.Left) .Append("' and '") .Append(be.Right) @@ -74,40 +73,34 @@ internal static Exception CreateUnsupportedNodeException(Expression node) return new NotSupportedException(sb.ToString()); } - /// - /// Gets the indexer property named "Item" from the specified type. - /// + /// Gets the indexer property named "Item" from the specified type. /// The type to retrieve the indexer property from. /// The for the "Item" indexer property. /// Thrown if no indexer property named "Item" is found. internal static PropertyInfo GetItemProperty( - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | - DynamicallyAccessedMemberTypes.NonPublicProperties)] + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties + | DynamicallyAccessedMemberTypes.NonPublicProperties)] Type type) { var property = type.GetRuntimeProperty("Item"); return property ?? throw new InvalidOperationException("Could not find a valid indexer property named 'Item'."); } - /// - /// Gets the "Length" property from the specified type. - /// + /// Gets the "Length" property from the specified type. /// The type to retrieve the Length property from. /// The for the "Length" property. /// Thrown if no "Length" property is found. internal static PropertyInfo GetLengthProperty( - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | - DynamicallyAccessedMemberTypes.NonPublicProperties)] + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties + | DynamicallyAccessedMemberTypes.NonPublicProperties)] Type type) { var property = type.GetRuntimeProperty("Length"); - return property ?? - throw new InvalidOperationException("Could not find valid information for the array length operator."); + return property + ?? throw new InvalidOperationException("Could not find valid information for the array length operator."); } - /// - /// Determines whether all expressions in the collection are instances. - /// + /// Determines whether all expressions in the collection are instances. /// The collection of expressions to check. /// if every expression is a ; otherwise . internal static bool AllConstant(ReadOnlyCollection expressions) @@ -123,9 +116,7 @@ internal static bool AllConstant(ReadOnlyCollection expressions) return true; } - /// - /// Visits each expression in an argument list and returns the visited results as an array. - /// + /// Visits each expression in an argument list and returns the visited results as an array. /// The argument expressions to visit. /// An array of visited argument expressions. internal Expression[] VisitArgumentList(ReadOnlyCollection arguments) diff --git a/src/ReactiveUI.Binding/Expression/Reflection.cs b/src/ReactiveUI.Binding/Expression/Reflection.cs index fbee775..58864ba 100644 --- a/src/ReactiveUI.Binding/Expression/Reflection.cs +++ b/src/ReactiveUI.Binding/Expression/Reflection.cs @@ -7,26 +7,21 @@ namespace ReactiveUI.Binding.Expressions; -/// -/// Helper class for handling reflection and expression-tree related operations. -/// +/// Helper class for handling reflection and expression-tree related operations. public static class Reflection { - /// - /// Singleton instance of the used for rewriting expression trees. - /// + /// Singleton instance of the used for rewriting expression trees. + private const string EmptyExpressionChainMessage = "Expression chain must contain at least one element."; + + /// The shared rewriter instance used to simplify expressions before inspection. private static readonly ExpressionRewriter ExpressionRewriterInstance = new(); - /// - /// Uses the expression re-writer to simplify the expression down to its simplest expression. - /// + /// Uses the expression re-writer to simplify the expression down to its simplest expression. /// The expression to rewrite. /// The rewritten expression. public static Expression Rewrite(Expression? expression) => ExpressionRewriterInstance.Visit(expression); - /// - /// Converts an expression that points to a property chain into a dotted path string. - /// + /// Converts an expression that points to a property chain into a dotted path string. /// The expression to generate the property names from. /// A string representation for the property chain the expression points to. public static string ExpressionToPropertyNames(Expression? expression) @@ -45,36 +40,30 @@ public static string ExpressionToPropertyNames(Expression? expression) if (!firstSegment) { - sb.Append('.'); + _ = sb.Append('.'); } - switch (exp.NodeType) + // Anything other than an indexer or member access contributes no name segment. + if (exp is IndexExpression { Indexer: not null } indexExpression) { - case ExpressionType.Index when - exp is IndexExpression { Indexer: not null } indexExpression: - { - sb.Append(indexExpression.Indexer.Name).Append('['); - - var args = indexExpression.Arguments; - for (var i = 0; i < args.Count; i++) - { - if (i != 0) - { - sb.Append(','); - } + _ = sb.Append(indexExpression.Indexer.Name).Append('['); - sb.Append(((ConstantExpression)args[i]).Value); - } - - sb.Append(']'); - break; - } - - case ExpressionType.MemberAccess when exp is MemberExpression memberExpression: + var args = indexExpression.Arguments; + for (var i = 0; i < args.Count; i++) + { + if (i != 0) { - sb.Append(memberExpression.Member.Name); - break; + _ = sb.Append(','); } + + _ = sb.Append(((ConstantExpression)args[i]).Value); + } + + _ = sb.Append(']'); + } + else if (exp is MemberExpression memberExpression) + { + _ = sb.Append(memberExpression.Member.Name); } firstSegment = false; @@ -83,9 +72,7 @@ public static string ExpressionToPropertyNames(Expression? expression) return sb.ToString(); } - /// - /// Converts a into a delegate which fetches the value for the member. - /// + /// Converts a into a delegate which fetches the value for the member. /// The member info to convert. /// A delegate that fetches the value, or null if unsupported. public static Func? GetValueFetcherForProperty(MemberInfo? member) @@ -101,18 +88,10 @@ public static string ExpressionToPropertyNames(Expression? expression) }; } - if (member is not PropertyInfo property) - { - return null; - } - - return property.GetValue; + return member is not PropertyInfo property ? null : property.GetValue; } - /// - /// Converts a into a delegate which fetches the value for the member. - /// Throws if the member is not a field or property. - /// + /// Converts a into a delegate which fetches the value for the member. Throws if the member is not a field or property. /// The member info to convert. /// A delegate that fetches the value. public static Func GetValueFetcherOrThrow(MemberInfo? member) @@ -120,13 +99,11 @@ public static string ExpressionToPropertyNames(Expression? expression) ArgumentExceptionHelper.ThrowIfNull(member); var ret = GetValueFetcherForProperty(member); - return ret ?? - throw new ArgumentException($"Type '{member!.DeclaringType}' must have a property '{member.Name}'"); + return ret + ?? throw new ArgumentException($"Type '{member!.DeclaringType}' must have a property '{member.Name}'"); } - /// - /// Converts a into a delegate which sets the value for the member. - /// + /// Converts a into a delegate which sets the value for the member. /// The member info to convert. /// A delegate that sets the value, or null if unsupported. public static Action? GetValueSetterForProperty(MemberInfo? member) @@ -138,18 +115,10 @@ public static string ExpressionToPropertyNames(Expression? expression) return (obj, val, _) => field.SetValue(obj, val); } - if (member is not PropertyInfo property) - { - return null; - } - - return property.SetValue; + return member is not PropertyInfo property ? null : property.SetValue; } - /// - /// Converts a into a delegate which sets the value for the member. - /// Throws if the member is not a field or property. - /// + /// Converts a into a delegate which sets the value for the member. Throws if the member is not a field or property. /// The member info to convert. /// A delegate that sets the value. public static Action GetValueSetterOrThrow(MemberInfo? member) @@ -157,13 +126,11 @@ public static string ExpressionToPropertyNames(Expression? expression) ArgumentExceptionHelper.ThrowIfNull(member); var ret = GetValueSetterForProperty(member); - return ret ?? - throw new ArgumentException($"Type '{member!.DeclaringType}' must have a property '{member.Name}'"); + return ret + ?? throw new ArgumentException($"Type '{member!.DeclaringType}' must have a property '{member.Name}'"); } - /// - /// Attempts to get the value of the last property in an expression chain. - /// + /// Attempts to get the value of the last property in an expression chain. /// The expected type of the final value. /// Receives the value if the chain can be evaluated. /// The object that starts the property chain. @@ -180,7 +147,7 @@ public static bool TryGetValueForPropertyChain( if (count == 0) { - throw new InvalidOperationException("Expression chain must contain at least one element."); + throw new InvalidOperationException(EmptyExpressionChainMessage); } for (var i = 0; i < count - 1; i++) @@ -209,9 +176,7 @@ public static bool TryGetValueForPropertyChain( return true; } - /// - /// Attempts to get all intermediate values in a property chain as observed changes. - /// + /// Attempts to get all intermediate values in a property chain as observed changes. /// Receives an array with one entry per expression in the chain. /// The object that starts the property chain. /// A sequence of expressions that point to properties/fields. @@ -229,7 +194,7 @@ public static bool TryGetAllValuesForPropertyChain( if (count == 0) { - throw new InvalidOperationException("Expression chain must contain at least one element."); + throw new InvalidOperationException(EmptyExpressionChainMessage); } var currentIndex = 0; @@ -263,10 +228,7 @@ public static bool TryGetAllValuesForPropertyChain( return true; } - /// - /// Attempts to set the value of the last property in an expression chain, throwing when reflection - /// members are missing. - /// + /// Attempts to set the value of the last property in an expression chain, throwing when reflection members are missing. /// The type of the end value being set. /// The object that starts the property chain. /// A sequence of expressions that point to properties/fields. @@ -279,9 +241,7 @@ public static bool TrySetValueToPropertyChain( TValue value) => TrySetValueToPropertyChain(target, expressionChain, value, true); - /// - /// Attempts to set the value of the last property in an expression chain. - /// + /// Attempts to set the value of the last property in an expression chain. /// The type of the end value being set. /// The object that starts the property chain. /// A sequence of expressions that point to properties/fields. @@ -300,7 +260,7 @@ public static bool TrySetValueToPropertyChain( if (count == 0) { - throw new InvalidOperationException("Expression chain must contain at least one element."); + throw new InvalidOperationException(EmptyExpressionChainMessage); } for (var i = 0; i < count - 1; i++) @@ -334,9 +294,7 @@ public static bool TrySetValueToPropertyChain( return TryInvokeSetter(setter, target, value, lastExpression.GetArgumentsArray()); } - /// - /// Materializes an expression chain into an array for indexed access, reusing the backing array when possible. - /// + /// Materializes an expression chain into an array for indexed access, reusing the backing array when possible. /// The expression chain to materialize. /// An array of expressions representing the chain. [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ReactiveUI.Binding/Fallback/CommandBindingAffinityChecker.cs b/src/ReactiveUI.Binding/Fallback/CommandBindingAffinityChecker.cs index d880585..95fa76a 100644 --- a/src/ReactiveUI.Binding/Fallback/CommandBindingAffinityChecker.cs +++ b/src/ReactiveUI.Binding/Fallback/CommandBindingAffinityChecker.cs @@ -13,24 +13,17 @@ namespace ReactiveUI.Binding.Fallback; /// override source-generated command binding at runtime. /// [EditorBrowsable(EditorBrowsableState.Never)] -[SuppressMessage( - "Major Code Smell", - "S4018:Generic methods should provide type parameter for type inference", - Justification = "The type parameter denotes the target type (value/control/view), supplied explicitly by callers; it is not derivable from the arguments. Public API.")] public static class CommandBindingAffinityChecker { - /// - /// Returns if any registered - /// implementation reports a higher affinity than - /// for the given control type. - /// + /// Returns if a registered outranks . /// The control type being bound to. /// The affinity of the source generator's selected plugin. /// Whether the caller specifies a custom event target. /// if a user plugin should override the generated binding. + [SuppressMessage("Design", "SST2307:Type parameters should be inferable", Justification = "Specified explicitly by the caller; the interface shape dictates it.")] public static bool HasHigherAffinityPlugin< - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents | - DynamicallyAccessedMemberTypes.PublicProperties)] + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents + | DynamicallyAccessedMemberTypes.PublicProperties)] T>(int generatedAffinity, bool hasEventTarget) { foreach (var plugin in Locator.Current.GetServices()) diff --git a/src/ReactiveUI.Binding/Fallback/ObservationAffinityChecker.cs b/src/ReactiveUI.Binding/Fallback/ObservationAffinityChecker.cs index 7846c50..b1bcfd8 100644 --- a/src/ReactiveUI.Binding/Fallback/ObservationAffinityChecker.cs +++ b/src/ReactiveUI.Binding/Fallback/ObservationAffinityChecker.cs @@ -15,11 +15,7 @@ namespace ReactiveUI.Binding.Fallback; [EditorBrowsable(EditorBrowsableState.Never)] public static class ObservationAffinityChecker { - /// - /// Returns if any registered - /// implementation reports a higher affinity than - /// for the given type. - /// + /// Returns if a registered outranks . /// The type being observed. /// The affinity of the source generator's selected plugin. /// Whether before-change (PropertyChanging) observation is requested. diff --git a/src/ReactiveUI.Binding/Fallback/RuntimeBindingConverter.cs b/src/ReactiveUI.Binding/Fallback/RuntimeBindingConverter.cs index 7b464ac..690b0a3 100644 --- a/src/ReactiveUI.Binding/Fallback/RuntimeBindingConverter.cs +++ b/src/ReactiveUI.Binding/Fallback/RuntimeBindingConverter.cs @@ -19,10 +19,7 @@ namespace ReactiveUI.Binding.Fallback; /// public static class RuntimeBindingConverter { - /// - /// Attempts to convert from to - /// for a generated BindTo assignment. - /// + /// Attempts to convert from to for a generated BindTo assignment. /// The declared source value type. /// The target property type. /// The value produced by the source observable. diff --git a/src/ReactiveUI.Binding/Fallback/RuntimeObservationFallback.cs b/src/ReactiveUI.Binding/Fallback/RuntimeObservationFallback.cs index dfe8858..6edb514 100644 --- a/src/ReactiveUI.Binding/Fallback/RuntimeObservationFallback.cs +++ b/src/ReactiveUI.Binding/Fallback/RuntimeObservationFallback.cs @@ -17,9 +17,7 @@ namespace ReactiveUI.Binding.Fallback; [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static class RuntimeObservationFallback { - /// - /// Runtime fallback for WhenChanged with a single property. - /// + /// Runtime fallback for WhenChanged with a single property. /// The type of object being observed. /// The type of the property value. /// The object to observe. @@ -34,12 +32,10 @@ public static IObservable WhenChanged( return new SelectObservable, TValue>( obj.SubscribeToExpressionChain(property.Body, skipInitial: false), - x => x.Value); + static x => x.Value); } - /// - /// Runtime fallback for multi-property WhenChanged, returning a tuple of values. - /// + /// Runtime fallback for multi-property WhenChanged, returning a tuple of values. /// The type of object being observed. /// The type of the first property value. /// The type of the second property value. @@ -55,12 +51,10 @@ public static IObservable WhenChanged( { var o1 = WhenChanged(obj, property1); var o2 = WhenChanged(obj, property2); - return CombineLatestObservable.Create(o1, o2, (v1, v2) => (v1, v2)); + return CombineLatestObservable.Create(o1, o2, static (v1, v2) => (v1, v2)); } - /// - /// Runtime fallback for multi-property WhenChanged with 3 properties. - /// + /// Runtime fallback for multi-property WhenChanged with 3 properties. /// The type of object being observed. /// The type of the first property value. /// The type of the second property value. @@ -80,12 +74,10 @@ public static IObservable WhenChanged( var o1 = WhenChanged(obj, property1); var o2 = WhenChanged(obj, property2); var o3 = WhenChanged(obj, property3); - return CombineLatestObservable.Create(o1, o2, o3, (v1, v2, v3) => (v1, v2, v3)); + return CombineLatestObservable.Create(o1, o2, o3, static (v1, v2, v3) => (v1, v2, v3)); } - /// - /// Runtime fallback for WhenChanging with a single property. - /// + /// Runtime fallback for WhenChanging with a single property. /// The type of object being observed. /// The type of the property value. /// The object to observe. @@ -100,12 +92,10 @@ public static IObservable WhenChanging( return new SelectObservable, TValue>( obj.SubscribeToExpressionChain(property.Body, true, false, true), - x => x.Value); + static x => x.Value); } - /// - /// Runtime fallback for multi-property WhenChanging with 2 properties. - /// + /// Runtime fallback for multi-property WhenChanging with 2 properties. /// The type of object being observed. /// The type of the first property value. /// The type of the second property value. @@ -121,12 +111,10 @@ public static IObservable WhenChanging( { var o1 = WhenChanging(obj, property1); var o2 = WhenChanging(obj, property2); - return CombineLatestObservable.Create(o1, o2, (v1, v2) => (v1, v2)); + return CombineLatestObservable.Create(o1, o2, static (v1, v2) => (v1, v2)); } - /// - /// Runtime fallback for multi-property WhenChanging with 3 properties. - /// + /// Runtime fallback for multi-property WhenChanging with 3 properties. /// The type of object being observed. /// The type of the first property value. /// The type of the second property value. @@ -146,12 +134,10 @@ public static IObservable WhenChanging( var o1 = WhenChanging(obj, property1); var o2 = WhenChanging(obj, property2); var o3 = WhenChanging(obj, property3); - return CombineLatestObservable.Create(o1, o2, o3, (v1, v2, v3) => (v1, v2, v3)); + return CombineLatestObservable.Create(o1, o2, o3, static (v1, v2, v3) => (v1, v2, v3)); } - /// - /// Runtime fallback for WhenAnyValue with a single property. - /// + /// Runtime fallback for WhenAnyValue with a single property. /// The type of object being observed. /// The type of the property value. /// The object to observe. @@ -166,12 +152,10 @@ public static IObservable WhenAnyValue( return new SelectObservable, TValue>( sender.SubscribeToExpressionChain(property.Body, skipInitial: false), - x => x.Value); + static x => x.Value); } - /// - /// Runtime fallback for multi-property WhenAnyValue with 2 properties. - /// + /// Runtime fallback for multi-property WhenAnyValue with 2 properties. /// The type of object being observed. /// The type of the first property value. /// The type of the second property value. @@ -187,12 +171,10 @@ public static IObservable WhenAnyValue( { var o1 = WhenAnyValue(sender, property1); var o2 = WhenAnyValue(sender, property2); - return CombineLatestObservable.Create(o1, o2, (v1, v2) => (v1, v2)); + return CombineLatestObservable.Create(o1, o2, static (v1, v2) => (v1, v2)); } - /// - /// Runtime fallback for multi-property WhenAnyValue with 3 properties. - /// + /// Runtime fallback for multi-property WhenAnyValue with 3 properties. /// The type of object being observed. /// The type of the first property value. /// The type of the second property value. @@ -212,6 +194,6 @@ public static IObservable WhenAnyValue( var o1 = WhenAnyValue(sender, property1); var o2 = WhenAnyValue(sender, property2); var o3 = WhenAnyValue(sender, property3); - return CombineLatestObservable.Create(o1, o2, o3, (v1, v2, v3) => (v1, v2, v3)); + return CombineLatestObservable.Create(o1, o2, o3, static (v1, v2, v3) => (v1, v2, v3)); } } diff --git a/src/ReactiveUI.Binding/Helpers/ArgumentExceptionHelper.cs b/src/ReactiveUI.Binding/Helpers/ArgumentExceptionHelper.cs index 6210dd2..dcc8164 100644 --- a/src/ReactiveUI.Binding/Helpers/ArgumentExceptionHelper.cs +++ b/src/ReactiveUI.Binding/Helpers/ArgumentExceptionHelper.cs @@ -15,12 +15,10 @@ namespace ReactiveUI.Binding.Helpers; [ExcludeFromCodeCoverage] internal static class ArgumentExceptionHelper { - /// - /// Throws an if is null. - /// + /// Throws an if is null. /// The reference type argument to validate as non-null. /// The name of the parameter with which corresponds. - public static void ThrowIfNull( + internal static void ThrowIfNull( [ValidatedNotNull][NotNull] object? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) @@ -33,13 +31,11 @@ public static void ThrowIfNull( throw new ArgumentNullException(paramName); } - /// - /// Throws an if is null. - /// + /// Throws an if is null. /// The reference type argument to validate as non-null. /// The exception message. /// The name of the parameter with which corresponds. - public static void ThrowIfNullWithMessage( + internal static void ThrowIfNullWithMessage( [ValidatedNotNull][NotNull] object? argument, string message, [CallerArgumentExpression(nameof(argument))] @@ -53,14 +49,12 @@ public static void ThrowIfNullWithMessage( throw new ArgumentNullException(paramName, message); } - /// - /// Throws an exception if is null or empty. - /// + /// Throws an exception if is null or empty. /// The string argument to validate as non-null and non-empty. /// The name of the parameter with which corresponds. /// is null. /// is empty. - public static void ThrowIfNullOrEmpty( + internal static void ThrowIfNullOrEmpty( [ValidatedNotNull][NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) @@ -78,14 +72,12 @@ public static void ThrowIfNullOrEmpty( throw new ArgumentException("The value cannot be an empty string.", paramName); } - /// - /// Throws an exception if is null, empty, or consists only of white-space characters. - /// + /// Throws an exception if is null, empty, or consists only of white-space characters. /// The string argument to validate. /// The name of the parameter with which corresponds. /// is null. /// is empty or consists only of white-space characters. - public static void ThrowIfNullOrWhiteSpace( + internal static void ThrowIfNullOrWhiteSpace( [ValidatedNotNull][NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) @@ -105,12 +97,10 @@ public static void ThrowIfNullOrWhiteSpace( paramName); } - /// - /// Throws an if is negative. - /// + /// Throws an if is negative. /// The argument to validate as non-negative. /// The name of the parameter with which corresponds. - public static void ThrowIfNegative(int value, [CallerArgumentExpression(nameof(value))] string? paramName = null) + internal static void ThrowIfNegative(int value, [CallerArgumentExpression(nameof(value))] string? paramName = null) { if (value >= 0) { @@ -120,13 +110,11 @@ public static void ThrowIfNegative(int value, [CallerArgumentExpression(nameof(v throw new ArgumentOutOfRangeException(paramName, "The value cannot be negative."); } - /// - /// Throws an if is true. - /// + /// Throws an if is true. /// The condition to evaluate. /// The exception message. /// The name of the parameter with which corresponds. - public static void ThrowIf( + internal static void ThrowIf( [DoesNotReturnIf(true)] bool condition, string message, [CallerArgumentExpression(nameof(condition))] @@ -140,12 +128,10 @@ public static void ThrowIf( throw new ArgumentException(message, paramName); } - /// - /// Throws an if is zero. - /// + /// Throws an if is zero. /// The argument to validate. /// The name of the parameter with which corresponds. - public static void ThrowIfZero(int value, [CallerArgumentExpression(nameof(value))] string? paramName = null) + internal static void ThrowIfZero(int value, [CallerArgumentExpression(nameof(value))] string? paramName = null) { if (value != 0) { @@ -155,12 +141,10 @@ public static void ThrowIfZero(int value, [CallerArgumentExpression(nameof(value throw new ArgumentOutOfRangeException(paramName, "The value cannot be zero."); } - /// - /// Throws an if is negative or zero. - /// + /// Throws an if is negative or zero. /// The argument to validate. /// The name of the parameter with which corresponds. - public static void ThrowIfNegativeOrZero( + internal static void ThrowIfNegativeOrZero( int value, [CallerArgumentExpression(nameof(value))] string? paramName = null) @@ -173,14 +157,12 @@ public static void ThrowIfNegativeOrZero( throw new ArgumentOutOfRangeException(paramName, "The value cannot be negative or zero."); } - /// - /// Throws an if is equal to . - /// + /// Throws an if is equal to . /// The type of the values to compare. /// The argument to validate. /// The value to compare with. /// The name of the parameter with which corresponds. - public static void ThrowIfEqual( + internal static void ThrowIfEqual( T value, T other, [CallerArgumentExpression(nameof(value))] @@ -195,14 +177,12 @@ public static void ThrowIfEqual( throw new ArgumentOutOfRangeException(paramName, $"The value cannot be equal to {other}."); } - /// - /// Throws an if is not equal to . - /// + /// Throws an if is not equal to . /// The type of the values to compare. /// The argument to validate. /// The value to compare with. /// The name of the parameter with which corresponds. - public static void ThrowIfNotEqual( + internal static void ThrowIfNotEqual( T value, T other, [CallerArgumentExpression(nameof(value))] @@ -217,14 +197,12 @@ public static void ThrowIfNotEqual( throw new ArgumentOutOfRangeException(paramName, $"The value must be equal to {other}."); } - /// - /// Throws an if is greater than . - /// + /// Throws an if is greater than . /// The type of the values to compare. /// The argument to validate. /// The value to compare with. /// The name of the parameter with which corresponds. - public static void ThrowIfGreaterThan( + internal static void ThrowIfGreaterThan( T value, T other, [CallerArgumentExpression(nameof(value))] @@ -239,14 +217,12 @@ public static void ThrowIfGreaterThan( throw new ArgumentOutOfRangeException(paramName, $"The value cannot be greater than {other}."); } - /// - /// Throws an if is greater than or equal to . - /// + /// Throws an if is greater than or equal to . /// The type of the values to compare. /// The argument to validate. /// The value to compare with. /// The name of the parameter with which corresponds. - public static void ThrowIfGreaterThanOrEqual( + internal static void ThrowIfGreaterThanOrEqual( T value, T other, [CallerArgumentExpression(nameof(value))] @@ -261,14 +237,12 @@ public static void ThrowIfGreaterThanOrEqual( throw new ArgumentOutOfRangeException(paramName, $"The value cannot be greater than or equal to {other}."); } - /// - /// Throws an if is less than . - /// + /// Throws an if is less than . /// The type of the values to compare. /// The argument to validate. /// The value to compare with. /// The name of the parameter with which corresponds. - public static void ThrowIfLessThan( + internal static void ThrowIfLessThan( T value, T other, [CallerArgumentExpression(nameof(value))] @@ -283,14 +257,12 @@ public static void ThrowIfLessThan( throw new ArgumentOutOfRangeException(paramName, $"The value cannot be less than {other}."); } - /// - /// Throws an if is less than or equal to . - /// + /// Throws an if is less than or equal to . /// The type of the values to compare. /// The argument to validate. /// The value to compare with. /// The name of the parameter with which corresponds. - public static void ThrowIfLessThanOrEqual( + internal static void ThrowIfLessThanOrEqual( T value, T other, [CallerArgumentExpression(nameof(value))] @@ -305,13 +277,11 @@ public static void ThrowIfLessThanOrEqual( throw new ArgumentOutOfRangeException(paramName, $"The value cannot be less than or equal to {other}."); } - /// - /// Throws an if is less than or equal to . - /// + /// Throws an if is less than or equal to . /// The argument to validate. /// The value to compare with. /// The name of the parameter with which corresponds. - public static void ThrowIfLessThanOrEqual( + internal static void ThrowIfLessThanOrEqual( int value, int other, [CallerArgumentExpression(nameof(value))] @@ -325,13 +295,11 @@ public static void ThrowIfLessThanOrEqual( throw new ArgumentOutOfRangeException(paramName, $"The value cannot be less than or equal to {other}."); } - /// - /// Throws an if is default. - /// + /// Throws an if is default. /// The struct type. /// The argument to validate. /// The name of the parameter with which corresponds. - public static void ThrowIfDefault( + internal static void ThrowIfDefault( T argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) diff --git a/src/ReactiveUI.Binding/Interactions/IInteraction.cs b/src/ReactiveUI.Binding/Interactions/IInteraction.cs index 6fc157e..fdf8cda 100644 --- a/src/ReactiveUI.Binding/Interactions/IInteraction.cs +++ b/src/ReactiveUI.Binding/Interactions/IInteraction.cs @@ -4,9 +4,7 @@ namespace ReactiveUI.Binding; -/// -/// Represents an interaction between collaborating application components. -/// +/// Represents an interaction between collaborating application components. /// /// /// Interactions allow collaborating components in an application to ask each other questions. Typically, @@ -23,31 +21,23 @@ namespace ReactiveUI.Binding; /// The interaction's output type. public interface IInteraction { - /// - /// Registers a synchronous interaction handler. - /// + /// Registers a synchronous interaction handler. /// The handler. /// A disposable which, when disposed, will unregister the handler. IDisposable RegisterHandler(Action> handler); - /// - /// Registers a task-based asynchronous interaction handler. - /// + /// Registers a task-based asynchronous interaction handler. /// The handler. /// A disposable which, when disposed, will unregister the handler. IDisposable RegisterHandler(Func, Task> handler); - /// - /// Registers an observable-based asynchronous interaction handler. - /// + /// Registers an observable-based asynchronous interaction handler. /// The signal type. /// The handler. /// A disposable which, when disposed, will unregister the handler. IDisposable RegisterHandler(Func, IObservable> handler); - /// - /// Handles an interaction and asynchronously returns the result. - /// + /// Handles an interaction and asynchronously returns the result. /// The input for the interaction. /// A task that completes with the output when the interaction is handled. Task Handle(TInput input); diff --git a/src/ReactiveUI.Binding/Interactions/IInteractionContext.cs b/src/ReactiveUI.Binding/Interactions/IInteractionContext.cs index dc3d830..9a50a2a 100644 --- a/src/ReactiveUI.Binding/Interactions/IInteractionContext.cs +++ b/src/ReactiveUI.Binding/Interactions/IInteractionContext.cs @@ -4,9 +4,7 @@ namespace ReactiveUI.Binding; -/// -/// Contains contextual information for an interaction. -/// +/// Contains contextual information for an interaction. /// /// /// Instances of this interface are passed into interaction handlers. The property exposes @@ -22,19 +20,13 @@ namespace ReactiveUI.Binding; /// The type of the interaction's output. public interface IInteractionContext { - /// - /// Gets the input for the interaction. - /// + /// Gets the input for the interaction. TInput Input { get; } - /// - /// Gets a value indicating whether the interaction is handled. That is, whether the output has been set. - /// + /// Gets a value indicating whether the interaction is handled. That is, whether the output has been set. bool IsHandled { get; } - /// - /// Sets the output for the interaction. - /// + /// Sets the output for the interaction. /// The output. void SetOutput(TOutput output); } diff --git a/src/ReactiveUI.Binding/Interactions/IOutputContext.cs b/src/ReactiveUI.Binding/Interactions/IOutputContext.cs index aee0975..242b60c 100644 --- a/src/ReactiveUI.Binding/Interactions/IOutputContext.cs +++ b/src/ReactiveUI.Binding/Interactions/IOutputContext.cs @@ -4,16 +4,12 @@ namespace ReactiveUI.Binding; -/// -/// Extends with the ability to retrieve the output. -/// +/// Extends with the ability to retrieve the output. /// The type of the interaction's input. /// The type of the interaction's output. public interface IOutputContext : IInteractionContext { - /// - /// Gets the output of the interaction. - /// + /// Gets the output of the interaction. /// The output. /// If the output has not been set. TOutput GetOutput(); diff --git a/src/ReactiveUI.Binding/Interactions/Interaction.cs b/src/ReactiveUI.Binding/Interactions/Interaction.cs index 000a614..7157881 100644 --- a/src/ReactiveUI.Binding/Interactions/Interaction.cs +++ b/src/ReactiveUI.Binding/Interactions/Interaction.cs @@ -6,9 +6,7 @@ namespace ReactiveUI.Binding; -/// -/// Represents an interaction between collaborating application components. -/// +/// Represents an interaction between collaborating application components. /// /// /// Interactions allow collaborating components in an application to ask each other questions. Typically, @@ -29,15 +27,11 @@ namespace ReactiveUI.Binding; /// The interaction's output type. public class Interaction : IInteraction { - /// - /// The list of registered interaction handlers, invoked in reverse order during . - /// + /// The list of registered interaction handlers, invoked in reverse order during . private readonly List, Task>> _handlers = []; - /// - /// Synchronization gate for thread-safe handler registration and removal. - /// - private readonly object _sync = new(); + /// Synchronization gate for thread-safe handler registration and removal. + private readonly Lock _sync = new(); /// public IDisposable RegisterHandler(Action> handler) @@ -68,8 +62,8 @@ public IDisposable RegisterHandler( Task ContentHandler(IInteractionContext context) { - var tcs = new TaskCompletionSource(); - handler(context).Subscribe(new ObservableToTaskObserver(tcs)); + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + _ = handler(context).Subscribe(new ObservableToTaskObserver(tcs)); return tcs.Task; } @@ -95,9 +89,7 @@ public virtual async Task Handle(TInput input) throw new UnhandledInteractionException(this, input); } - /// - /// Gets all registered handlers by order of registration. - /// + /// Gets all registered handlers by order of registration. /// All registered handlers. protected Func, Task>[] GetHandlers() { @@ -107,17 +99,13 @@ protected Func, Task>[] GetHandlers() } } - /// - /// Gets an interaction context which is used to provide information about the interaction. - /// + /// Gets an interaction context which is used to provide information about the interaction. /// The input that is being passed in. /// The interaction context. - protected virtual IOutputContext GenerateContext(TInput input) - => new InteractionContext(input); + protected virtual IOutputContext GenerateContext(TInput input) => + new InteractionContext(input); - /// - /// Adds a handler to the internal handler list under the synchronization gate. - /// + /// Adds a handler to the internal handler list under the synchronization gate. /// The handler to add. private void AddHandler(Func, Task> handler) { @@ -127,33 +115,24 @@ private void AddHandler(Func, Task> handler } } - /// - /// Removes a handler from the internal handler list under the synchronization gate. - /// + /// Removes a handler from the internal handler list under the synchronization gate. /// The handler to remove. private void RemoveHandler(Func, Task> handler) { lock (_sync) { - _handlers.Remove(handler); + _ = _handlers.Remove(handler); } } - /// - /// An observer that bridges an observable sequence to a , - /// completing the task when the observable completes or faults. - /// + /// An observer that bridges an observable sequence to a , completing the task when the observable completes or faults. /// The element type of the observable sequence. private sealed class ObservableToTaskObserver : IObserver { - /// - /// The task completion source that is signaled when the observable completes or errors. - /// + /// The task completion source that is signaled when the observable completes or errors. private readonly TaskCompletionSource _tcs; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The task completion source to signal. public ObservableToTaskObserver(TaskCompletionSource tcs) => _tcs = tcs; diff --git a/src/ReactiveUI.Binding/Interactions/InteractionContext.cs b/src/ReactiveUI.Binding/Interactions/InteractionContext.cs index 5e82e8f..b5dfe39 100644 --- a/src/ReactiveUI.Binding/Interactions/InteractionContext.cs +++ b/src/ReactiveUI.Binding/Interactions/InteractionContext.cs @@ -4,9 +4,7 @@ namespace ReactiveUI.Binding; -/// -/// Contains contextual information for an interaction. -/// +/// Contains contextual information for an interaction. /// /// /// Instances of this class are passed into interaction handlers. The property exposes @@ -23,19 +21,13 @@ namespace ReactiveUI.Binding; /// The type of the interaction's output. public sealed class InteractionContext : IOutputContext { - /// - /// The output value set by a handler via . - /// + /// The output value set by a handler via . private TOutput _output = default!; - /// - /// Tracks whether the output has been set (0 = not set, 1 = set). - /// + /// Tracks whether the output has been set (0 = not set, 1 = set). private int _outputSet; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The input value for this interaction. internal InteractionContext(TInput input) => Input = input; @@ -43,7 +35,7 @@ public sealed class InteractionContext : IOutputContext - public bool IsHandled => _outputSet == 1; + public bool IsHandled => Volatile.Read(ref _outputSet) == 1; /// public void SetOutput(TOutput output) @@ -59,7 +51,7 @@ public void SetOutput(TOutput output) /// public TOutput GetOutput() { - if (_outputSet == 0) + if (Volatile.Read(ref _outputSet) == 0) { throw new InvalidOperationException("Output has not been set."); } @@ -67,9 +59,7 @@ public TOutput GetOutput() return _output; } - /// - /// Atomically claims the output slot. - /// + /// Atomically claims the output slot. /// if the claim was successful; if already set. [ExcludeFromCodeCoverage] [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ReactiveUI.Binding/Interactions/UnhandledInteractionException.cs b/src/ReactiveUI.Binding/Interactions/UnhandledInteractionException.cs index 71e7cb6..ac3f094 100644 --- a/src/ReactiveUI.Binding/Interactions/UnhandledInteractionException.cs +++ b/src/ReactiveUI.Binding/Interactions/UnhandledInteractionException.cs @@ -4,16 +4,12 @@ namespace ReactiveUI.Binding; -/// -/// Indicates that an interaction has gone unhandled. -/// +/// Indicates that an interaction has gone unhandled. /// The type of the interaction's input. /// The type of the interaction's output. public class UnhandledInteractionException : Exception { - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The interaction that doesn't have an input handler. /// The input into the interaction. public UnhandledInteractionException(Interaction interaction, TInput input) @@ -23,25 +19,19 @@ public UnhandledInteractionException(Interaction interaction, T Input = input; } - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. public UnhandledInteractionException() { } - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// A message about the exception. public UnhandledInteractionException(string message) : base(message) { } - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// A message about the exception. /// Any other exception that caused the issue. public UnhandledInteractionException(string message, Exception innerException) @@ -49,13 +39,9 @@ public UnhandledInteractionException(string message, Exception innerException) { } - /// - /// Gets the interaction that was not handled. - /// + /// Gets the interaction that was not handled. public Interaction? Interaction { get; } - /// - /// Gets the input for the interaction that was not handled. - /// + /// Gets the input for the interaction that was not handled. public TInput Input { get; } = default!; } diff --git a/src/ReactiveUI.Binding/Interfaces/BindingDirection.cs b/src/ReactiveUI.Binding/Interfaces/BindingDirection.cs index ed54003..3aa22f2 100644 --- a/src/ReactiveUI.Binding/Interfaces/BindingDirection.cs +++ b/src/ReactiveUI.Binding/Interfaces/BindingDirection.cs @@ -4,23 +4,15 @@ namespace ReactiveUI.Binding; -/// -/// Specifies the direction of a property binding. -/// +/// Specifies the direction of a property binding. public enum BindingDirection { - /// - /// One-way binding from source to target. - /// + /// One-way binding from source to target. OneWay, - /// - /// Two-way binding between source and target. - /// + /// Two-way binding between source and target. TwoWay, - /// - /// One-way asynchronous binding from source to target. - /// + /// One-way asynchronous binding from source to target. AsyncOneWay } diff --git a/src/ReactiveUI.Binding/Interfaces/CreatesObservableForPropertyMixin.cs b/src/ReactiveUI.Binding/Interfaces/CreatesObservableForPropertyMixin.cs deleted file mode 100644 index c40fda9..0000000 --- a/src/ReactiveUI.Binding/Interfaces/CreatesObservableForPropertyMixin.cs +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) 2019-2026 ReactiveUI Association Incorporated. All rights reserved. -// ReactiveUI Association Incorporated licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -namespace ReactiveUI.Binding; - -/// -/// Convenience overloads for that supply the common -/// defaults. They are provided as overloads (rather than optional parameters on the interface) so the -/// interface stays free of optional parameters and works on target frameworks without default interface methods. -/// -public static class CreatesObservableForPropertyMixin -{ - /// - /// Returns the affinity for after-change observation of the specified property. - /// - /// The observation factory. - /// The type being observed. - /// The property name being observed. - /// The affinity score. Positive means supported. - public static int GetAffinityForObject(this ICreatesObservableForProperty factory, Type type, string propertyName) - { - ArgumentExceptionHelper.ThrowIfNull(factory); - return factory.GetAffinityForObject(type, propertyName, false); - } - - /// - /// Creates an observable that fires after the specified property changes, without suppressing warnings. - /// - /// The observation factory. - /// The object to observe. - /// The expression identifying the property. - /// The property name. - /// An observable of observed changes. - public static IObservable> GetNotificationForProperty( - this ICreatesObservableForProperty factory, - object sender, - Expression expression, - string propertyName) - { - ArgumentExceptionHelper.ThrowIfNull(factory); - return factory.GetNotificationForProperty(sender, expression, propertyName, false, false); - } - - /// - /// Creates an observable that fires when the specified property changes, without suppressing warnings. - /// - /// The observation factory. - /// The object to observe. - /// The expression identifying the property. - /// The property name. - /// Whether to observe before-change events. - /// An observable of observed changes. - public static IObservable> GetNotificationForProperty( - this ICreatesObservableForProperty factory, - object sender, - Expression expression, - string propertyName, - bool beforeChanged) - { - ArgumentExceptionHelper.ThrowIfNull(factory); - return factory.GetNotificationForProperty(sender, expression, propertyName, beforeChanged, false); - } -} diff --git a/src/ReactiveUI.Binding/Interfaces/CreatesObservableForPropertyMixins.cs b/src/ReactiveUI.Binding/Interfaces/CreatesObservableForPropertyMixins.cs new file mode 100644 index 0000000..1f3519e --- /dev/null +++ b/src/ReactiveUI.Binding/Interfaces/CreatesObservableForPropertyMixins.cs @@ -0,0 +1,58 @@ +// Copyright (c) 2019-2026 ReactiveUI Association Incorporated. All rights reserved. +// ReactiveUI Association Incorporated licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +namespace ReactiveUI.Binding; + +/// +/// Convenience overloads for that supply the common +/// defaults. They are provided as overloads (rather than optional parameters on the interface) so the +/// interface stays free of optional parameters and works on target frameworks without default interface methods. +/// +public static class CreatesObservableForPropertyMixins +{ + /// Provides GetAffinityForObject extension members for . + /// The observation factory. + extension(ICreatesObservableForProperty factory) + { + /// Returns the affinity for after-change observation of the specified property. + /// The type being observed. + /// The property name being observed. + /// The affinity score. Positive means supported. + public int GetAffinityForObject(Type type, string propertyName) + { + ArgumentExceptionHelper.ThrowIfNull(factory); + return factory.GetAffinityForObject(type, propertyName, false); + } + + /// Creates an observable that fires after the specified property changes, without suppressing warnings. + /// The object to observe. + /// The expression identifying the property. + /// The property name. + /// An observable of observed changes. + public IObservable> GetNotificationForProperty( + object sender, + Expression expression, + string propertyName) + { + ArgumentExceptionHelper.ThrowIfNull(factory); + return factory.GetNotificationForProperty(sender, expression, propertyName, false, false); + } + + /// Creates an observable that fires when the specified property changes, without suppressing warnings. + /// The object to observe. + /// The expression identifying the property. + /// The property name. + /// Whether to observe before-change events. + /// An observable of observed changes. + public IObservable> GetNotificationForProperty( + object sender, + Expression expression, + string propertyName, + bool beforeChanged) + { + ArgumentExceptionHelper.ThrowIfNull(factory); + return factory.GetNotificationForProperty(sender, expression, propertyName, beforeChanged, false); + } + } +} diff --git a/src/ReactiveUI.Binding/Interfaces/IActivatableView.cs b/src/ReactiveUI.Binding/Interfaces/IActivatableView.cs index 1f6f7b5..d5d4220 100644 --- a/src/ReactiveUI.Binding/Interfaces/IActivatableView.cs +++ b/src/ReactiveUI.Binding/Interfaces/IActivatableView.cs @@ -4,8 +4,6 @@ namespace ReactiveUI.Binding; -/// -/// Marker interface for views that support activation and deactivation lifecycle events. -/// -[SuppressMessage("Design", "CA1040:Avoid empty interfaces", Justification = "Marker interface")] +/// Marker interface for views that support activation and deactivation lifecycle events. +[SuppressMessage("Design", "SST1437:Empty interface", Justification = "Intentional marker interface.")] public interface IActivatableView; diff --git a/src/ReactiveUI.Binding/Interfaces/ICreatesCommandBinding.cs b/src/ReactiveUI.Binding/Interfaces/ICreatesCommandBinding.cs index 3ec6c06..1ec7fe8 100644 --- a/src/ReactiveUI.Binding/Interfaces/ICreatesCommandBinding.cs +++ b/src/ReactiveUI.Binding/Interfaces/ICreatesCommandBinding.cs @@ -22,10 +22,6 @@ namespace ReactiveUI.Binding; /// properties, WinForms event-based binding). /// /// -[SuppressMessage( - "Major Code Smell", - "S4018:Generic methods should provide type parameter for type inference", - Justification = "The type parameter denotes the target type (value/control/view), supplied explicitly by callers; it is not derivable from the arguments. Public API.")] public interface ICreatesCommandBinding { /// @@ -37,9 +33,11 @@ public interface ICreatesCommandBinding /// The type of the control to bind to. /// Whether the caller specifies a custom event target. /// A positive integer if binding is supported, or zero/negative if not. + [SuppressMessage("Design", "SST2307:Type parameters should be inferable", Justification = "Specified explicitly by the caller; the interface shape dictates it.")] + [SuppressMessage("Design", "SST1452:Unused type parameter", Justification = "Carries the trimming annotation for the control type; implementations resolve it via typeof(T).")] int GetAffinityForObject< - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents | - DynamicallyAccessedMemberTypes.PublicProperties)] + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents + | DynamicallyAccessedMemberTypes.PublicProperties)] T>(bool hasEventTarget); /// @@ -50,28 +48,34 @@ int GetAffinityForObject< /// The command to bind. If , no binding is created. /// The target object, usually a UI control. /// An observable that provides the command parameter value. - /// An that disconnects the binding when disposed, or if no binding was created. + /// + /// An that disconnects the binding when disposed, or + /// if no binding was created. + /// [RequiresUnreferencedCode("String/reflection-based event binding may require members removed by trimming.")] IDisposable? BindCommandToObject< - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | - DynamicallyAccessedMemberTypes.PublicEvents | - DynamicallyAccessedMemberTypes.NonPublicEvents)] + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties + | DynamicallyAccessedMemberTypes.PublicEvents + | DynamicallyAccessedMemberTypes.NonPublicEvents)] T>( ICommand? command, T? target, IObservable commandParameter) where T : class; - /// - /// Binds an to a UI object to a specific named event. - /// + /// Binds an to a UI object to a specific named event. /// The type of the target object. /// The event argument type. /// The command to bind. If , no binding is created. /// The target object, usually a UI control. /// An observable that provides the command parameter value. /// The event to bind to. - /// An that disconnects the binding when disposed, or if no binding was created. + /// + /// An that disconnects the binding when disposed, or + /// if no binding was created. + /// + [SuppressMessage("Design", "SST2307:Type parameters should be inferable", Justification = "Specified explicitly by the caller; it identifies the bound command shape.")] + [SuppressMessage("Design", "SST1452:Unused type parameter", Justification = "Types the event handler this overload binds; it mirrors the add/remove handler overload.")] [RequiresUnreferencedCode("String/reflection-based event binding may require members removed by trimming.")] IDisposable? BindCommandToObject( ICommand? command, @@ -93,9 +97,9 @@ int GetAffinityForObject< /// Removes the handler from the target event. /// A disposable that unbinds the command. IDisposable? BindCommandToObject< - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | - DynamicallyAccessedMemberTypes.PublicEvents | - DynamicallyAccessedMemberTypes.NonPublicEvents)] + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties + | DynamicallyAccessedMemberTypes.PublicEvents + | DynamicallyAccessedMemberTypes.NonPublicEvents)] T, TEventArgs>( ICommand? command, T? target, diff --git a/src/ReactiveUI.Binding/Interfaces/ICreatesObservableForProperty.cs b/src/ReactiveUI.Binding/Interfaces/ICreatesObservableForProperty.cs index d606cf2..cc0b77b 100644 --- a/src/ReactiveUI.Binding/Interfaces/ICreatesObservableForProperty.cs +++ b/src/ReactiveUI.Binding/Interfaces/ICreatesObservableForProperty.cs @@ -24,9 +24,7 @@ public interface ICreatesObservableForProperty /// The affinity score. Positive means supported. int GetAffinityForObject(Type type, string propertyName, bool beforeChanged); - /// - /// Creates an observable that fires when the specified property changes. - /// + /// Creates an observable that fires when the specified property changes. /// The object to observe. /// The expression identifying the property. /// The property name. diff --git a/src/ReactiveUI.Binding/Interfaces/IObservedChange.cs b/src/ReactiveUI.Binding/Interfaces/IObservedChange.cs index 50fdaa1..f0ddeab 100644 --- a/src/ReactiveUI.Binding/Interfaces/IObservedChange.cs +++ b/src/ReactiveUI.Binding/Interfaces/IObservedChange.cs @@ -4,25 +4,17 @@ namespace ReactiveUI.Binding; -/// -/// Represents the result of a property change observation. -/// +/// Represents the result of a property change observation. /// The type of the object that raised the change. /// The type of the property value. public interface IObservedChange { - /// - /// Gets the object that raised the change. - /// + /// Gets the object that raised the change. TSender Sender { get; } - /// - /// Gets the expression of the member that changed. - /// + /// Gets the expression of the member that changed. Expression? Expression { get; } - /// - /// Gets the current value of the property. - /// + /// Gets the current value of the property. TValue Value { get; } } diff --git a/src/ReactiveUI.Binding/Interfaces/IPropertyBindingHook.cs b/src/ReactiveUI.Binding/Interfaces/IPropertyBindingHook.cs index 82d628a..3c5a20d 100644 --- a/src/ReactiveUI.Binding/Interfaces/IPropertyBindingHook.cs +++ b/src/ReactiveUI.Binding/Interfaces/IPropertyBindingHook.cs @@ -10,9 +10,7 @@ namespace ReactiveUI.Binding; /// public interface IPropertyBindingHook { - /// - /// Called when any binding is set up. - /// + /// Called when any binding is set up. /// If false, the binding is cancelled. /// The source ViewModel. /// The target View (not the actual control). diff --git a/src/ReactiveUI.Binding/Interfaces/IReactiveBinding.cs b/src/ReactiveUI.Binding/Interfaces/IReactiveBinding.cs index e0999cc..6dedaab 100644 --- a/src/ReactiveUI.Binding/Interfaces/IReactiveBinding.cs +++ b/src/ReactiveUI.Binding/Interfaces/IReactiveBinding.cs @@ -4,36 +4,24 @@ namespace ReactiveUI.Binding; -/// -/// Represents a binding between a view and a view model property. -/// +/// Represents a binding between a view and a view model property. /// The type of the view. /// The type of the bound value. public interface IReactiveBinding : IDisposable where TView : IViewFor { - /// - /// Gets the expression representing the view model property that is bound. - /// + /// Gets the expression representing the view model property that is bound. Expression? ViewModelExpression { get; } - /// - /// Gets the view that is bound. - /// + /// Gets the view that is bound. TView View { get; } - /// - /// Gets the expression representing the view property that is bound. - /// + /// Gets the expression representing the view property that is bound. Expression? ViewExpression { get; } - /// - /// Gets an observable that signals when the binding value changes. - /// + /// Gets an observable that signals when the binding value changes. IObservable Changed { get; } - /// - /// Gets the direction of the binding. - /// + /// Gets the direction of the binding. BindingDirection Direction { get; } } diff --git a/src/ReactiveUI.Binding/Interfaces/IViewFor.cs b/src/ReactiveUI.Binding/Interfaces/IViewFor.cs index 87b7947..026a869 100644 --- a/src/ReactiveUI.Binding/Interfaces/IViewFor.cs +++ b/src/ReactiveUI.Binding/Interfaces/IViewFor.cs @@ -4,13 +4,9 @@ namespace ReactiveUI.Binding; -/// -/// Non-generic interface for views that display a view model. -/// +/// Non-generic interface for views that display a view model. public interface IViewFor : IActivatableView { - /// - /// Gets or sets the view model displayed by the view. - /// + /// Gets or sets the view model displayed by the view. object? ViewModel { get; set; } } diff --git a/src/ReactiveUI.Binding/Interfaces/IViewFor{T}.cs b/src/ReactiveUI.Binding/Interfaces/IViewFor{T}.cs index a596d3b..a19afb9 100644 --- a/src/ReactiveUI.Binding/Interfaces/IViewFor{T}.cs +++ b/src/ReactiveUI.Binding/Interfaces/IViewFor{T}.cs @@ -4,15 +4,11 @@ namespace ReactiveUI.Binding; -/// -/// Generic interface for views that display a specific view model type. -/// +/// Generic interface for views that display a specific view model type. /// The type of the view model. public interface IViewFor : IViewFor where T : class { - /// - /// Gets or sets the view model displayed by the view. - /// + /// Gets or sets the view model displayed by the view. new T? ViewModel { get; set; } } diff --git a/src/ReactiveUI.Binding/Interfaces/IViewLocator.cs b/src/ReactiveUI.Binding/Interfaces/IViewLocator.cs index 2951e4c..6610242 100644 --- a/src/ReactiveUI.Binding/Interfaces/IViewLocator.cs +++ b/src/ReactiveUI.Binding/Interfaces/IViewLocator.cs @@ -10,10 +10,7 @@ namespace ReactiveUI.Binding; /// public interface IViewLocator : IEnableLogger { - /// - /// Resolves a view for the specified view model type. - /// This overload is AOT-safe when registered mappings are available. - /// + /// Resolves a view for the specified view model type. This overload is AOT-safe when registered mappings are available. /// The type of the view model. /// The view model instance to resolve a view for. /// An optional contract string for named registrations. diff --git a/src/ReactiveUI.Binding/Interfaces/ObservedChange.cs b/src/ReactiveUI.Binding/Interfaces/ObservedChange.cs index 304e2b0..3feb7d6 100644 --- a/src/ReactiveUI.Binding/Interfaces/ObservedChange.cs +++ b/src/ReactiveUI.Binding/Interfaces/ObservedChange.cs @@ -4,16 +4,12 @@ namespace ReactiveUI.Binding; -/// -/// Concrete implementation of . -/// +/// Concrete implementation of . /// The type of the object that raised the change. /// The type of the property value. public class ObservedChange : IObservedChange { - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The object that raised the change. /// The expression of the member that changed. /// The current value of the property. diff --git a/src/ReactiveUI.Binding/Interfaces/ViewLocatorMixin.cs b/src/ReactiveUI.Binding/Interfaces/ViewLocatorMixin.cs deleted file mode 100644 index 2a14bad..0000000 --- a/src/ReactiveUI.Binding/Interfaces/ViewLocatorMixin.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2019-2026 ReactiveUI Association Incorporated. All rights reserved. -// ReactiveUI Association Incorporated licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -namespace ReactiveUI.Binding; - -/// -/// Convenience overloads for that supply the default (null) contract. -/// Provided as overloads rather than optional parameters so the interface stays free of optional parameters. -/// -public static class ViewLocatorMixin -{ - /// - /// Resolves a view for the specified view model type using the default contract. - /// - /// The type of the view model. - /// The view locator. - /// The view model instance to resolve a view for. - /// The resolved view, or if no view is found. - public static IViewFor? ResolveView(this IViewLocator locator, TViewModel viewModel) - where TViewModel : class - { - ArgumentExceptionHelper.ThrowIfNull(locator); - return locator.ResolveView(viewModel, null); - } - - /// - /// Resolves a view for the specified view model instance using the default contract. - /// - /// The view locator. - /// The view model instance to resolve a view for. - /// The resolved view, or if no view is found. - public static IViewFor? ResolveView(this IViewLocator locator, object? viewModel) - { - ArgumentExceptionHelper.ThrowIfNull(locator); - return locator.ResolveView(viewModel, null); - } -} diff --git a/src/ReactiveUI.Binding/Interfaces/ViewLocatorMixins.cs b/src/ReactiveUI.Binding/Interfaces/ViewLocatorMixins.cs new file mode 100644 index 0000000..215997e --- /dev/null +++ b/src/ReactiveUI.Binding/Interfaces/ViewLocatorMixins.cs @@ -0,0 +1,37 @@ +// Copyright (c) 2019-2026 ReactiveUI Association Incorporated. All rights reserved. +// ReactiveUI Association Incorporated licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +namespace ReactiveUI.Binding; + +/// +/// Convenience overloads for that supply the default (null) contract. +/// Provided as overloads rather than optional parameters so the interface stays free of optional parameters. +/// +public static class ViewLocatorMixins +{ + /// Provides ResolveView extension members for . + /// The view locator. + extension(IViewLocator locator) + { + /// Resolves a view for the specified view model type using the default contract. + /// The type of the view model. + /// The view model instance to resolve a view for. + /// The resolved view, or if no view is found. + public IViewFor? ResolveView(TViewModel viewModel) + where TViewModel : class + { + ArgumentExceptionHelper.ThrowIfNull(locator); + return locator.ResolveView(viewModel, null); + } + + /// Resolves a view for the specified view model instance using the default contract. + /// The view model instance to resolve a view for. + /// The resolved view, or if no view is found. + public IViewFor? ResolveView(object? viewModel) + { + ArgumentExceptionHelper.ThrowIfNull(locator); + return locator.ResolveView(viewModel, null); + } + } +} diff --git a/src/ReactiveUI.Binding/Mixins/.editorconfig b/src/ReactiveUI.Binding/Mixins/.editorconfig new file mode 100644 index 0000000..40c8c1f --- /dev/null +++ b/src/ReactiveUI.Binding/Mixins/.editorconfig @@ -0,0 +1,24 @@ +[*.cs] + +################### +# Runtime dispatch stubs +# +# The generator emits a concrete typed overload of each of these methods as a classic static +# extension method, because generated output has to compile as C# 7.3. A binding only reaches its +# generated implementation if that concrete overload wins extension lookup against the stub here. +# +# Rewriting a stub as an extension block member changes that outcome: the stub starts winning, and +# every generated binding falls through to the runtime path and throws "No generated binding found" +# (measured - 78 runtime-execution tests fail with the block form and pass with the classic form). +# These stubs therefore stay classic extension methods. +################### +dotnet_diagnostic.SST1703.severity = none # an extension block member outranks the generated overload +dotnet_diagnostic.SST1705.severity = none # an extension block member outranks the generated overload +dotnet_diagnostic.SST1708.severity = none # an extension block member outranks the generated overload + +# The selector overloads declare their signature once per #if arm and share one expression body +# after the #endif. SST1527 wants the arrow at the end of the preceding line - which is the #endif - +# and moving it would push the body inside a single arm. Rewriting them as block bodies instead +# trades the rule for SST2275, which asks for the expression body back, so the two cannot both be +# satisfied for this shape. +dotnet_diagnostic.SST1527.severity = none # the arrow follows an #endif shared by both arms diff --git a/src/ReactiveUI.Binding/Mixins/BuilderMixins.cs b/src/ReactiveUI.Binding/Mixins/BuilderMixins.cs index 0b6f758..da8b302 100644 --- a/src/ReactiveUI.Binding/Mixins/BuilderMixins.cs +++ b/src/ReactiveUI.Binding/Mixins/BuilderMixins.cs @@ -7,10 +7,7 @@ namespace ReactiveUI.Binding.Mixins; -/// -/// Extension methods that bridge to -/// for fluent chaining. -/// +/// Extension methods that bridge to for fluent chaining. /// /// These methods allow fluent chains such as: /// @@ -23,16 +20,12 @@ namespace ReactiveUI.Binding.Mixins; /// public static class BuilderMixins { - /// - /// Message used when an is not an . - /// + /// Message used when an is not an . private const string NotBindingBuilderMessage = - "The provided IAppBuilder is not an IReactiveUIBindingBuilder. " + - "Ensure you are using the ReactiveUI.Binding builder pattern."; + "The provided IAppBuilder is not an IReactiveUIBindingBuilder. " + + "Ensure you are using the ReactiveUI.Binding builder pattern."; - /// - /// Builds the ReactiveUI.Binding application from an . - /// + /// Builds the ReactiveUI.Binding application from an . /// The app builder instance. /// The configured application instance. /// @@ -50,9 +43,7 @@ public static IReactiveUIBindingInstance BuildApp(this IAppBuilder appBuilder) return reactiveUiBindingBuilder.BuildApp(); } - /// - /// Registers a platform-specific module from an . - /// + /// Registers a platform-specific module from an . /// The type of the platform module. /// The app builder instance. /// The platform module instance to register. @@ -73,9 +64,7 @@ public static IReactiveUIBindingBuilder WithPlatformModule(this IAppBuilder a return reactiveUiBindingBuilder.WithPlatformModule(module); } - /// - /// Adds a custom registration action from an . - /// + /// Adds a custom registration action from an . /// The app builder instance. /// An action that receives the mutable dependency resolver. /// The builder instance for chaining. @@ -96,9 +85,7 @@ public static IReactiveUIBindingBuilder WithRegistration( return reactiveUiBindingBuilder.WithRegistration(configureAction); } - /// - /// Registers a typed binding converter from an . - /// + /// Registers a typed binding converter from an . /// The app builder instance. /// The converter instance to register. /// The builder instance for chaining. @@ -117,9 +104,7 @@ public static IReactiveUIBindingBuilder WithConverter(this IAppBuilder appBuilde return reactiveUiBindingBuilder.WithConverter(converter); } - /// - /// Registers a fallback binding converter from an . - /// + /// Registers a fallback binding converter from an . /// The app builder instance. /// The fallback converter instance to register. /// The builder instance for chaining. @@ -140,9 +125,7 @@ public static IReactiveUIBindingBuilder WithFallbackConverter( return reactiveUiBindingBuilder.WithFallbackConverter(converter); } - /// - /// Registers a set-method binding converter from an . - /// + /// Registers a set-method binding converter from an . /// The app builder instance. /// The set-method converter instance to register. /// The builder instance for chaining. @@ -163,9 +146,7 @@ public static IReactiveUIBindingBuilder WithSetMethodConverter( return reactiveUiBindingBuilder.WithSetMethodConverter(converter); } - /// - /// Configures the default view locator with explicit view-to-view-model mappings from an . - /// + /// Configures the default view locator with explicit view-to-view-model mappings from an . /// The app builder instance. /// An action that receives a for registering mappings. /// The builder instance for chaining. diff --git a/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.BindCommand.cs b/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.BindCommand.cs index 6addc71..8f67de1 100644 --- a/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.BindCommand.cs +++ b/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.BindCommand.cs @@ -2,19 +2,16 @@ // ReactiveUI Association Incorporated licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System.Diagnostics.CodeAnalysis; using System.Windows.Input; namespace ReactiveUI.Binding; -/// -/// Extension methods for binding commands from a view model to controls on a view. -/// +/// Extension methods for binding commands from a view model to controls on a view. public static partial class ReactiveUIBindingExtensions { #if NET8_0_OR_GREATER - /// - /// Binds a command from a view model to a control on a view. - /// + /// Binds a command from a view model to a control on a view. /// The type of the view. /// The type of the view model. /// The type of the command property. @@ -29,6 +26,8 @@ public static partial class ReactiveUIBindingExtensions /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// A disposable that, when disposed, disconnects the binding. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST2309", Justification = "the CallerInfo and toEvent defaults must stay optional; overloads would shadow the generated overloads")] public static IDisposable BindCommand( this TView view, TViewModel? viewModel, @@ -44,9 +43,7 @@ public static IDisposable BindCommand( where TProp : ICommand where TControl : class #else - /// - /// Binds a command from a view model to a control on a view. - /// + /// Binds a command from a view model to a control on a view. /// The type of the view. /// The type of the view model. /// The type of the command property. @@ -59,6 +56,8 @@ public static IDisposable BindCommand( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// A disposable that, when disposed, disconnects the binding. + [SuppressMessage("Design", "SST2309", Justification = "the CallerInfo defaults must stay optional; overloads would shadow the generated overloads")] + [SuppressMessage("Design", "SST2309", Justification = "the CallerInfo and toEvent defaults must stay optional; overloads would shadow the generated overloads")] public static IDisposable BindCommand( this TView view, TViewModel? viewModel, @@ -77,9 +76,7 @@ public static IDisposable BindCommand( } #if NET8_0_OR_GREATER - /// - /// Binds a command from a view model to a control on a view with an observable parameter. - /// + /// Binds a command from a view model to a control on a view with an observable parameter. /// The type of the view. /// The type of the view model. /// The type of the command property. @@ -96,6 +93,8 @@ public static IDisposable BindCommand( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// A disposable that, when disposed, disconnects the binding. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST2309", Justification = "the CallerInfo and toEvent defaults must stay optional; overloads would shadow the generated overloads")] public static IDisposable BindCommand( this TView view, TViewModel? viewModel, @@ -112,9 +111,7 @@ public static IDisposable BindCommand - /// Binds a command from a view model to a control on a view with an observable parameter. - /// + /// Binds a command from a view model to a control on a view with an observable parameter. /// The type of the view. /// The type of the view model. /// The type of the command property. @@ -129,6 +126,9 @@ public static IDisposable BindCommandThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// A disposable that, when disposed, disconnects the binding. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST2309", Justification = "the CallerInfo defaults must stay optional; overloads would shadow the generated overloads")] + [SuppressMessage("Design", "SST2309", Justification = "the CallerInfo and toEvent defaults must stay optional; overloads would shadow the generated overloads")] public static IDisposable BindCommand( this TView view, TViewModel? viewModel, @@ -148,9 +148,7 @@ public static IDisposable BindCommand - /// Binds a command from a view model to a control on a view with a parameter expression. - /// + /// Binds a command from a view model to a control on a view with a parameter expression. /// The type of the view. /// The type of the view model. /// The type of the command property. @@ -168,6 +166,8 @@ public static IDisposable BindCommandThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// A disposable that, when disposed, disconnects the binding. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST2309", Justification = "the CallerInfo and toEvent defaults must stay optional; overloads would shadow the generated overloads")] public static IDisposable BindCommand( this TView view, TViewModel? viewModel, @@ -185,9 +185,7 @@ public static IDisposable BindCommand - /// Binds a command from a view model to a control on a view with a parameter expression. - /// + /// Binds a command from a view model to a control on a view with a parameter expression. /// The type of the view. /// The type of the view model. /// The type of the command property. @@ -202,6 +200,9 @@ public static IDisposable BindCommandThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// A disposable that, when disposed, disconnects the binding. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST2309", Justification = "the CallerInfo defaults must stay optional; overloads would shadow the generated overloads")] + [SuppressMessage("Design", "SST2309", Justification = "the CallerInfo and toEvent defaults must stay optional; overloads would shadow the generated overloads")] public static IDisposable BindCommand( this TView view, TViewModel? viewModel, diff --git a/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.BindInteraction.cs b/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.BindInteraction.cs index 9910789..bc20115 100644 --- a/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.BindInteraction.cs +++ b/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.BindInteraction.cs @@ -4,15 +4,11 @@ namespace ReactiveUI.Binding; -/// -/// Extension methods for binding interactions between a view and a view model. -/// +/// Extension methods for binding interactions between a view and a view model. public static partial class ReactiveUIBindingExtensions { #if NET8_0_OR_GREATER - /// - /// Binds a task-based handler to an interaction exposed by the view model. - /// + /// Binds a task-based handler to an interaction exposed by the view model. /// The type of the view model. /// The type of the view. /// The type of the interaction's input. @@ -37,9 +33,7 @@ public static IDisposable BindInteraction( where TViewModel : class where TView : class, IViewFor #else - /// - /// Binds a task-based handler to an interaction exposed by the view model. - /// + /// Binds a task-based handler to an interaction exposed by the view model. /// The type of the view model. /// The type of the view. /// The type of the interaction's input. @@ -66,9 +60,7 @@ public static IDisposable BindInteraction( } #if NET8_0_OR_GREATER - /// - /// Binds an observable-based handler to an interaction exposed by the view model. - /// + /// Binds an observable-based handler to an interaction exposed by the view model. /// The type of the view model. /// The type of the view. /// The type of the interaction's input. @@ -94,9 +86,7 @@ public static IDisposable BindInteraction - /// Binds an observable-based handler to an interaction exposed by the view model. - /// + /// Binds an observable-based handler to an interaction exposed by the view model. /// The type of the view model. /// The type of the view. /// The type of the interaction's input. diff --git a/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.BindTo.cs b/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.BindTo.cs index 8a07b23..6ebe8bb 100644 --- a/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.BindTo.cs +++ b/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.BindTo.cs @@ -12,10 +12,7 @@ namespace ReactiveUI.Binding; public static partial class ReactiveUIBindingExtensions { #if NET8_0_OR_GREATER - /// - /// Applies an observable stream to a target property. Conceptually similar to - /// source.Subscribe(x => target.property = x). - /// + /// Applies an observable stream to a target property. Conceptually similar to source.Subscribe(x => target.property = x). /// The type of the value produced by the source observable. /// The type of the target object. /// The type of the property on the target object. @@ -35,10 +32,7 @@ public static IDisposable BindTo( [CallerLineNumber] int callerLineNumber = 0) where TTarget : class #else - /// - /// Applies an observable stream to a target property. Conceptually similar to - /// source.Subscribe(x => target.property = x). - /// + /// Applies an observable stream to a target property. Conceptually similar to source.Subscribe(x => target.property = x). /// The type of the value produced by the source observable. /// The type of the target object. /// The type of the property on the target object. @@ -183,6 +177,7 @@ public static IDisposable BindTo( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// A disposable that, when disposed, disconnects the binding. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IDisposable BindTo( this IObservable source, TTarget? target, diff --git a/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.Binding.cs b/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.Binding.cs index 5073406..0f006cc 100644 --- a/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.Binding.cs +++ b/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.Binding.cs @@ -4,15 +4,11 @@ namespace ReactiveUI.Binding; -/// -/// Extension methods for property binding (BindOneWay, BindTwoWay, OneWayBind, Bind). -/// +/// Extension methods for property binding (BindOneWay, BindTwoWay, OneWayBind, Bind). public static partial class ReactiveUIBindingExtensions { #if NET8_0_OR_GREATER - /// - /// Creates a one-way binding from a source property to a target property. - /// + /// Creates a one-way binding from a source property to a target property. /// The type of the source object. /// The type of the target object. /// The type of the property being bound. @@ -25,6 +21,7 @@ public static partial class ReactiveUIBindingExtensions /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// A disposable that, when disposed, disconnects the binding. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IDisposable BindOneWay( this TSource source, TTarget target, @@ -39,9 +36,7 @@ public static IDisposable BindOneWay( where TSource : class where TTarget : class #else - /// - /// Creates a one-way binding from a source property to a target property. - /// + /// Creates a one-way binding from a source property to a target property. /// The type of the source object. /// The type of the target object. /// The type of the property being bound. @@ -67,9 +62,7 @@ public static IDisposable BindOneWay( } #if NET8_0_OR_GREATER - /// - /// Creates a one-way binding from a source property to a target property with a conversion function. - /// + /// Creates a one-way binding from a source property to a target property with a conversion function. /// The type of the source object. /// The type of the source property. /// The type of the target object. @@ -84,6 +77,7 @@ public static IDisposable BindOneWay( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// A disposable that, when disposed, disconnects the binding. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IDisposable BindOneWay( this TSource source, TTarget target, @@ -99,9 +93,7 @@ public static IDisposable BindOneWay where TSource : class where TTarget : class #else - /// - /// Creates a one-way binding from a source property to a target property with a conversion function. - /// + /// Creates a one-way binding from a source property to a target property with a conversion function. /// The type of the source object. /// The type of the source property. /// The type of the target object. @@ -130,9 +122,7 @@ public static IDisposable BindOneWay } #if NET8_0_OR_GREATER - /// - /// Creates a two-way binding between a source property and a target property. - /// + /// Creates a two-way binding between a source property and a target property. /// The type of the source object. /// The type of the target object. /// The type of the property being bound. @@ -145,6 +135,7 @@ public static IDisposable BindOneWay /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// A disposable that, when disposed, disconnects the binding. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IDisposable BindTwoWay( this TSource source, TTarget target, @@ -159,9 +150,7 @@ public static IDisposable BindTwoWay( where TSource : class where TTarget : class #else - /// - /// Creates a two-way binding between a source property and a target property. - /// + /// Creates a two-way binding between a source property and a target property. /// The type of the source object. /// The type of the target object. /// The type of the property being bound. @@ -187,9 +176,7 @@ public static IDisposable BindTwoWay( } #if NET8_0_OR_GREATER - /// - /// Creates a two-way binding between a source property and a target property with conversion functions. - /// + /// Creates a two-way binding between a source property and a target property with conversion functions. /// The type of the source object. /// The type of the source property. /// The type of the target object. @@ -205,6 +192,7 @@ public static IDisposable BindTwoWay( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// A disposable that, when disposed, disconnects the binding. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IDisposable BindTwoWay( this TSource source, TTarget target, @@ -221,9 +209,7 @@ public static IDisposable BindTwoWay where TSource : class where TTarget : class #else - /// - /// Creates a two-way binding between a source property and a target property with conversion functions. - /// + /// Creates a two-way binding between a source property and a target property with conversion functions. /// The type of the source object. /// The type of the source property. /// The type of the target object. @@ -237,6 +223,7 @@ public static IDisposable BindTwoWay /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// A disposable that, when disposed, disconnects the binding. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IDisposable BindTwoWay( this TSource source, TTarget target, @@ -254,29 +241,28 @@ public static IDisposable BindTwoWay } #if NET8_0_OR_GREATER - /// - /// Creates a one-way binding from a view model property to a view property. - /// + /// Creates a one-way binding from a view model property to a view property. /// The type of the view model. /// The type of the view. /// The type of the view model property. /// The type of the view property. /// The view to bind to. /// The view model to observe. - /// An expression that selects the view model property to observe. + /// An expression that selects the view model property to observe. /// An expression that selects the view property to update. - /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. /// The caller argument expression for . Auto-populated by the compiler. /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// A reactive binding that can be disposed to disconnect the binding. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IReactiveBinding OneWayBind( this TView view, TViewModel viewModel, - Expression> vmProperty, + Expression> viewModelProperty, Expression> viewProperty, - [CallerArgumentExpression("vmProperty")] - string vmPropertyExpression = "", + [CallerArgumentExpression("viewModelProperty")] + string viewModelPropertyExpression = "", [CallerArgumentExpression("viewProperty")] string viewPropertyExpression = "", [CallerFilePath] string callerFilePath = "", @@ -284,16 +270,14 @@ public static IReactiveBinding OneWayBind - /// Creates a one-way binding from a view model property to a view property. - /// + /// Creates a one-way binding from a view model property to a view property. /// The type of the view model. /// The type of the view. /// The type of the view model property. /// The type of the view property. /// The view to bind to. /// The view model to observe. - /// An expression that selects the view model property to observe. + /// An expression that selects the view model property to observe. /// An expression that selects the view property to update. /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. @@ -301,7 +285,7 @@ public static IReactiveBinding OneWayBind OneWayBind( this TView view, TViewModel viewModel, - Expression> vmProperty, + Expression> viewModelProperty, Expression> viewProperty, [CallerFilePath] string callerFilePath = "", [CallerLineNumber] int callerLineNumber = 0) @@ -313,31 +297,30 @@ public static IReactiveBinding OneWayBind - /// Creates a one-way binding from a view model property to a view property with a specified selector. - /// + /// Creates a one-way binding from a view model property to a view property with a specified selector. /// The type of the view model. /// The type of the view. /// The type of the view model property. /// The type of the view property. /// The view to bind to. /// The view model to observe. - /// An expression that selects the view model property to observe. + /// An expression that selects the view model property to observe. /// An expression that selects the view property to update. /// A function that converts the view model property value to the view property type. - /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. /// The caller argument expression for . Auto-populated by the compiler. /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// A reactive binding that can be disposed to disconnect the binding. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IReactiveBinding OneWayBind( this TView view, TViewModel viewModel, - Expression> vmProperty, + Expression> viewModelProperty, Expression> viewProperty, Func selector, - [CallerArgumentExpression("vmProperty")] - string vmPropertyExpression = "", + [CallerArgumentExpression("viewModelProperty")] + string viewModelPropertyExpression = "", [CallerArgumentExpression("viewProperty")] string viewPropertyExpression = "", [CallerFilePath] string callerFilePath = "", @@ -345,16 +328,14 @@ public static IReactiveBinding OneWayBind - /// Creates a one-way binding from a view model property to a view property with a specified selector. - /// + /// Creates a one-way binding from a view model property to a view property with a specified selector. /// The type of the view model. /// The type of the view. /// The type of the view model property. /// The type of the view property. /// The view to bind to. /// The view model to observe. - /// An expression that selects the view model property to observe. + /// An expression that selects the view model property to observe. /// An expression that selects the view property to update. /// A function that converts the view model property value to the view property type. /// The source file path of the caller. Auto-populated by the compiler. @@ -363,7 +344,7 @@ public static IReactiveBinding OneWayBind OneWayBind( this TView view, TViewModel viewModel, - Expression> vmProperty, + Expression> viewModelProperty, Expression> viewProperty, Func selector, [CallerFilePath] string callerFilePath = "", @@ -376,29 +357,28 @@ public static IReactiveBinding OneWayBind - /// Creates a two-way binding between a view model property and a view property. - /// + /// Creates a two-way binding between a view model property and a view property. /// The type of the view model. /// The type of the view. /// The type of the view model property. /// The type of the view property. /// The view to bind to. /// The view model to observe. - /// An expression that selects the view model property to observe. + /// An expression that selects the view model property to observe. /// An expression that selects the view property to update. - /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. /// The caller argument expression for . Auto-populated by the compiler. /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// A reactive binding that can be disposed to disconnect the binding. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IReactiveBinding Bind( this TView view, TViewModel viewModel, - Expression> vmProperty, + Expression> viewModelProperty, Expression> viewProperty, - [CallerArgumentExpression("vmProperty")] - string vmPropertyExpression = "", + [CallerArgumentExpression("viewModelProperty")] + string viewModelPropertyExpression = "", [CallerArgumentExpression("viewProperty")] string viewPropertyExpression = "", [CallerFilePath] string callerFilePath = "", @@ -406,16 +386,14 @@ public static IReactiveBinding OneWayBind - /// Creates a two-way binding between a view model property and a view property. - /// + /// Creates a two-way binding between a view model property and a view property. /// The type of the view model. /// The type of the view. /// The type of the view model property. /// The type of the view property. /// The view to bind to. /// The view model to observe. - /// An expression that selects the view model property to observe. + /// An expression that selects the view model property to observe. /// An expression that selects the view property to update. /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. @@ -423,7 +401,7 @@ public static IReactiveBinding OneWayBind Bind( this TView view, TViewModel viewModel, - Expression> vmProperty, + Expression> viewModelProperty, Expression> viewProperty, [CallerFilePath] string callerFilePath = "", [CallerLineNumber] int callerLineNumber = 0) @@ -435,33 +413,32 @@ public static IReactiveBinding OneWayBind - /// Creates a two-way binding between a view model property and a view property with conversion functions. - /// + /// Creates a two-way binding between a view model property and a view property with conversion functions. /// The type of the view model. /// The type of the view. /// The type of the view model property. /// The type of the view property. /// The view to bind to. /// The view model to observe. - /// An expression that selects the view model property to observe. + /// An expression that selects the view model property to observe. /// An expression that selects the view property to update. - /// A function that converts the view model property value to the view property type. - /// A function that converts the view property value back to the view model property type. - /// The caller argument expression for . Auto-populated by the compiler. + /// A function that converts the view model property value to the view property type. + /// A function that converts the view property value back to the view model property type. + /// The caller argument expression for . Auto-populated by the compiler. /// The caller argument expression for . Auto-populated by the compiler. /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// A reactive binding that can be disposed to disconnect the binding. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IReactiveBinding Bind( this TView view, TViewModel viewModel, - Expression> vmProperty, + Expression> viewModelProperty, Expression> viewProperty, - Func vmToViewConverter, - Func viewToVmConverter, - [CallerArgumentExpression("vmProperty")] - string vmPropertyExpression = "", + Func viewModelToViewConverter, + Func viewToViewModelConverter, + [CallerArgumentExpression("viewModelProperty")] + string viewModelPropertyExpression = "", [CallerArgumentExpression("viewProperty")] string viewPropertyExpression = "", [CallerFilePath] string callerFilePath = "", @@ -469,29 +446,28 @@ public static IReactiveBinding OneWayBind - /// Creates a two-way binding between a view model property and a view property with conversion functions. - /// + /// Creates a two-way binding between a view model property and a view property with conversion functions. /// The type of the view model. /// The type of the view. /// The type of the view model property. /// The type of the view property. /// The view to bind to. /// The view model to observe. - /// An expression that selects the view model property to observe. + /// An expression that selects the view model property to observe. /// An expression that selects the view property to update. - /// A function that converts the view model property value to the view property type. - /// A function that converts the view property value back to the view model property type. + /// A function that converts the view model property value to the view property type. + /// A function that converts the view property value back to the view model property type. /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// A reactive binding that can be disposed to disconnect the binding. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IReactiveBinding Bind( this TView view, TViewModel viewModel, - Expression> vmProperty, + Expression> viewModelProperty, Expression> viewProperty, - Func vmToViewConverter, - Func viewToVmConverter, + Func viewModelToViewConverter, + Func viewToViewModelConverter, [CallerFilePath] string callerFilePath = "", [CallerLineNumber] int callerLineNumber = 0) where TViewModel : class diff --git a/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenAny.cs b/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenAny.cs index e2ff48d..4d1b0ad 100644 --- a/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenAny.cs +++ b/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenAny.cs @@ -2,20 +2,18 @@ // ReactiveUI Association Incorporated licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System.Diagnostics.CodeAnalysis; using ReactiveUI.Binding.ObservableForProperty; + using ReactiveUI.Binding.Observables; namespace ReactiveUI.Binding; -/// -/// Extension methods for observing property changes with IObservedChange context (WhenAny). -/// +/// Extension methods for observing property changes with IObservedChange context (WhenAny). public static partial class ReactiveUIBindingExtensions { #if NET8_0_OR_GREATER - /// - /// Observes 1 property on the specified sender and applies a selector to the observed changes. - /// + /// Observes 1 property on the specified sender and applies a selector to the observed changes. /// The type of the sender to monitor for property changes. /// The return type of the selector. /// The type of property 1 value. @@ -37,9 +35,7 @@ public static IObservable WhenAny( [CallerLineNumber] int callerLineNumber = 0) where TSender : class #else - /// - /// Observes 1 property on the specified sender and applies a selector to the observed changes. - /// + /// Observes 1 property on the specified sender and applies a selector to the observed changes. /// The type of the sender to monitor for property changes. /// The return type of the selector. /// The type of property 1 value. @@ -69,9 +65,7 @@ public static IObservable WhenAny( } #if NET8_0_OR_GREATER - /// - /// Observes 2 properties on the specified sender and applies a selector to the observed changes. - /// + /// Observes 2 properties on the specified sender and applies a selector to the observed changes. /// The type of the sender to monitor for property changes. /// The return type of the selector. /// The type of property 1 value. @@ -85,6 +79,7 @@ public static IObservable WhenAny( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAny( this TSender sender, @@ -99,9 +94,7 @@ public static IObservable WhenAny( [CallerLineNumber] int callerLineNumber = 0) where TSender : class #else - /// - /// Observes 2 properties on the specified sender and applies a selector to the observed changes. - /// + /// Observes 2 properties on the specified sender and applies a selector to the observed changes. /// The type of the sender to monitor for property changes. /// The return type of the selector. /// The type of property 1 value. @@ -142,9 +135,7 @@ public static IObservable WhenAny( } #if NET8_0_OR_GREATER - /// - /// Observes 3 properties on the specified sender and applies a selector to the observed changes. - /// + /// Observes 3 properties on the specified sender and applies a selector to the observed changes. /// The type of the sender to monitor for property changes. /// The return type of the selector. /// The type of property 1 value. @@ -161,6 +152,8 @@ public static IObservable WhenAny( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAny( this TSender sender, @@ -178,9 +171,7 @@ public static IObservable WhenAny( [CallerLineNumber] int callerLineNumber = 0) where TSender : class #else - /// - /// Observes 3 properties on the specified sender and applies a selector to the observed changes. - /// + /// Observes 3 properties on the specified sender and applies a selector to the observed changes. /// The type of the sender to monitor for property changes. /// The return type of the selector. /// The type of property 1 value. @@ -229,9 +220,7 @@ public static IObservable WhenAny( } #if NET8_0_OR_GREATER - /// - /// Observes 4 properties on the specified sender and applies a selector to the observed changes. - /// + /// Observes 4 properties on the specified sender and applies a selector to the observed changes. /// The type of the sender to monitor for property changes. /// The return type of the selector. /// The type of property 1 value. @@ -251,6 +240,8 @@ public static IObservable WhenAny( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAny( this TSender sender, @@ -276,9 +267,7 @@ public static IObservable WhenAny( [CallerLineNumber] int callerLineNumber = 0) where TSender : class #else - /// - /// Observes 4 properties on the specified sender and applies a selector to the observed changes. - /// + /// Observes 4 properties on the specified sender and applies a selector to the observed changes. /// The type of the sender to monitor for property changes. /// The return type of the selector. /// The type of property 1 value. @@ -294,6 +283,7 @@ public static IObservable WhenAny( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAny( this TSender sender, @@ -335,9 +325,7 @@ public static IObservable WhenAny( } #if NET8_0_OR_GREATER - /// - /// Observes 5 properties on the specified sender and applies a selector to the observed changes. - /// + /// Observes 5 properties on the specified sender and applies a selector to the observed changes. /// The type of the sender to monitor for property changes. /// The return type of the selector. /// The type of property 1 value. @@ -360,6 +348,8 @@ public static IObservable WhenAny( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAny( this TSender sender, @@ -389,9 +379,7 @@ public static IObservable WhenAny( [CallerLineNumber] int callerLineNumber = 0) where TSender : class #else - /// - /// Observes 5 properties on the specified sender and applies a selector to the observed changes. - /// + /// Observes 5 properties on the specified sender and applies a selector to the observed changes. /// The type of the sender to monitor for property changes. /// The return type of the selector. /// The type of property 1 value. @@ -409,6 +397,7 @@ public static IObservable WhenAny( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAny( this TSender sender, @@ -456,9 +445,7 @@ public static IObservable WhenAny( } #if NET8_0_OR_GREATER - /// - /// Observes 6 properties on the specified sender and applies a selector to the observed changes. - /// + /// Observes 6 properties on the specified sender and applies a selector to the observed changes. /// The type of the sender to monitor for property changes. /// The return type of the selector. /// The type of property 1 value. @@ -484,6 +471,8 @@ public static IObservable WhenAny( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAny( this TSender sender, @@ -517,9 +506,7 @@ public static IObservable WhenAny( [CallerLineNumber] int callerLineNumber = 0) where TSender : class #else - /// - /// Observes 6 properties on the specified sender and applies a selector to the observed changes. - /// + /// Observes 6 properties on the specified sender and applies a selector to the observed changes. /// The type of the sender to monitor for property changes. /// The return type of the selector. /// The type of property 1 value. @@ -539,6 +526,7 @@ public static IObservable WhenAny( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAny( this TSender sender, @@ -599,9 +587,7 @@ public static IObservable WhenAny( } #if NET8_0_OR_GREATER - /// - /// Observes 7 properties on the specified sender and applies a selector to the observed changes. - /// + /// Observes 7 properties on the specified sender and applies a selector to the observed changes. /// The type of the sender to monitor for property changes. /// The return type of the selector. /// The type of property 1 value. @@ -630,6 +616,8 @@ public static IObservable WhenAny( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAny( this TSender sender, @@ -667,9 +655,7 @@ public static IObservable WhenAny - /// Observes 7 properties on the specified sender and applies a selector to the observed changes. - /// + /// Observes 7 properties on the specified sender and applies a selector to the observed changes. /// The type of the sender to monitor for property changes. /// The return type of the selector. /// The type of property 1 value. @@ -691,6 +677,8 @@ public static IObservable WhenAnyThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAny( this TSender sender, @@ -758,9 +746,7 @@ public static IObservable WhenAny - /// Observes 8 properties on the specified sender and applies a selector to the observed changes. - /// + /// Observes 8 properties on the specified sender and applies a selector to the observed changes. /// The type of the sender to monitor for property changes. /// The return type of the selector. /// The type of property 1 value. @@ -792,6 +778,8 @@ public static IObservable WhenAnyThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAny( this TSender sender, @@ -833,9 +821,7 @@ public static IObservable WhenAny - /// Observes 8 properties on the specified sender and applies a selector to the observed changes. - /// + /// Observes 8 properties on the specified sender and applies a selector to the observed changes. /// The type of the sender to monitor for property changes. /// The return type of the selector. /// The type of property 1 value. @@ -859,6 +845,8 @@ public static IObservable WhenAnyThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAny( this TSender sender, @@ -933,9 +921,7 @@ public static IObservable WhenAny - /// Observes 9 properties on the specified sender and applies a selector to the observed changes. - /// + /// Observes 9 properties on the specified sender and applies a selector to the observed changes. /// The type of the sender to monitor for property changes. /// The return type of the selector. /// The type of property 1 value. @@ -970,6 +956,8 @@ public static IObservable WhenAnyThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAny( this TSender sender, @@ -1015,9 +1003,7 @@ public static IObservable WhenAny - /// Observes 9 properties on the specified sender and applies a selector to the observed changes. - /// + /// Observes 9 properties on the specified sender and applies a selector to the observed changes. /// The type of the sender to monitor for property changes. /// The return type of the selector. /// The type of property 1 value. @@ -1043,6 +1029,8 @@ public static IObservable WhenAnyThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAny( this TSender sender, @@ -1124,9 +1112,7 @@ public static IObservable WhenAny - /// Observes 10 properties on the specified sender and applies a selector to the observed changes. - /// + /// Observes 10 properties on the specified sender and applies a selector to the observed changes. /// The type of the sender to monitor for property changes. /// The return type of the selector. /// The type of property 1 value. @@ -1164,6 +1150,8 @@ public static IObservable WhenAnyThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAny( this TSender sender, @@ -1213,9 +1201,7 @@ public static IObservable WhenAny - /// Observes 10 properties on the specified sender and applies a selector to the observed changes. - /// + /// Observes 10 properties on the specified sender and applies a selector to the observed changes. /// The type of the sender to monitor for property changes. /// The return type of the selector. /// The type of property 1 value. @@ -1243,6 +1229,8 @@ public static IObservable WhenAnyThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAny( this TSender sender, @@ -1331,9 +1319,7 @@ public static IObservable WhenAny - /// Observes 11 properties on the specified sender and applies a selector to the observed changes. - /// + /// Observes 11 properties on the specified sender and applies a selector to the observed changes. /// The type of the sender to monitor for property changes. /// The return type of the selector. /// The type of property 1 value. @@ -1374,6 +1360,8 @@ public static IObservable WhenAnyThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAny( this TSender sender, @@ -1427,9 +1415,7 @@ public static IObservable WhenAny - /// Observes 11 properties on the specified sender and applies a selector to the observed changes. - /// + /// Observes 11 properties on the specified sender and applies a selector to the observed changes. /// The type of the sender to monitor for property changes. /// The return type of the selector. /// The type of property 1 value. @@ -1459,6 +1445,8 @@ public static IObservable WhenAnyThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAny( this TSender sender, @@ -1554,9 +1542,7 @@ public static IObservable WhenAny - /// Observes 12 properties on the specified sender and applies a selector to the observed changes. - /// + /// Observes 12 properties on the specified sender and applies a selector to the observed changes. /// The type of the sender to monitor for property changes. /// The return type of the selector. /// The type of property 1 value. @@ -1600,6 +1586,8 @@ public static IObservable WhenAnyThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAny( this TSender sender, @@ -1657,9 +1645,7 @@ public static IObservable WhenAny - /// Observes 12 properties on the specified sender and applies a selector to the observed changes. - /// + /// Observes 12 properties on the specified sender and applies a selector to the observed changes. /// The type of the sender to monitor for property changes. /// The return type of the selector. /// The type of property 1 value. @@ -1691,6 +1677,8 @@ public static IObservable WhenAnyThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAny( this TSender sender, diff --git a/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenAnyObservable.Extended.cs b/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenAnyObservable.Extended.cs new file mode 100644 index 0000000..d55106a --- /dev/null +++ b/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenAnyObservable.Extended.cs @@ -0,0 +1,1319 @@ +// Copyright (c) 2019-2026 ReactiveUI Association Incorporated. All rights reserved. +// ReactiveUI Association Incorporated licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +using System.Diagnostics.CodeAnalysis; +using ReactiveUI.Binding.Observables; + +namespace ReactiveUI.Binding; + +/// +/// The higher-arity WhenAnyObservable overloads. They live in their own file so neither half of +/// this partial class grows past the file-length limit. +/// +public static partial class ReactiveUIBindingExtensions +{ +#if NET8_0_OR_GREATER + /// + /// Observes 3 observable properties with different types on the specified sender and applies a selector to the combined latest values. + /// + /// The type of the sender to monitor for property changes. + /// The return type of the selector. + /// The element type of observable property 1. + /// The element type of observable property 2. + /// The element type of observable property 3. + /// The sender instance to observe for property changes. + /// An expression that selects observable property 1 to observe. + /// An expression that selects observable property 2 to observe. + /// An expression that selects observable property 3 to observe. + /// A function that combines the latest values from all observables. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] + public static IObservable WhenAnyObservable( + this TSender sender, + Expression?>> obs1, + Expression?>> obs2, + Expression?>> obs3, + Func selector, + [CallerArgumentExpression("obs1")] string obs1Expression = "", + [CallerArgumentExpression("obs2")] string obs2Expression = "", + [CallerArgumentExpression("obs3")] string obs3Expression = "", + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TSender : class +#else + /// + /// Observes 3 observable properties with different types on the specified sender and applies a selector to the combined latest values. + /// + /// The type of the sender to monitor for property changes. + /// The return type of the selector. + /// The element type of observable property 1. + /// The element type of observable property 2. + /// The element type of observable property 3. + /// The sender instance to observe for property changes. + /// An expression that selects observable property 1 to observe. + /// An expression that selects observable property 2 to observe. + /// An expression that selects observable property 3 to observe. + /// A function that combines the latest values from all observables. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// An observable sequence of selector results. + [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] + public static IObservable WhenAnyObservable( + this TSender sender, + Expression?>> obs1, + Expression?>> obs2, + Expression?>> obs3, + Func selector, + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TSender : class +#endif + { + ArgumentExceptionHelper.ThrowIfNull(sender); + ArgumentExceptionHelper.ThrowIfNull(obs1); + ArgumentExceptionHelper.ThrowIfNull(obs2); + ArgumentExceptionHelper.ThrowIfNull(obs3); + ArgumentExceptionHelper.ThrowIfNull(selector); + + var o1 = ObservableChainHelpers.SwitchLatest(sender, obs1); + var o2 = ObservableChainHelpers.SwitchLatest(sender, obs2); + var o3 = ObservableChainHelpers.SwitchLatest(sender, obs3); + return CombineLatestObservable.Create( + o1, + o2, + o3, + (v1, v2, v3) => selector(v1, v2, v3)); + } + +#if NET8_0_OR_GREATER + /// + /// Observes 4 observable properties with different types on the specified sender and applies a selector to the combined latest values. + /// + /// The type of the sender to monitor for property changes. + /// The return type of the selector. + /// The element type of observable property 1. + /// The element type of observable property 2. + /// The element type of observable property 3. + /// The element type of observable property 4. + /// The sender instance to observe for property changes. + /// An expression that selects observable property 1 to observe. + /// An expression that selects observable property 2 to observe. + /// An expression that selects observable property 3 to observe. + /// An expression that selects observable property 4 to observe. + /// A function that combines the latest values from all observables. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] + public static IObservable WhenAnyObservable( + this TSender sender, + Expression?>> obs1, + Expression?>> obs2, + Expression?>> obs3, + Expression?>> obs4, + Func selector, + [CallerArgumentExpression("obs1")] string obs1Expression = "", + [CallerArgumentExpression("obs2")] string obs2Expression = "", + [CallerArgumentExpression("obs3")] string obs3Expression = "", + [CallerArgumentExpression("obs4")] string obs4Expression = "", + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TSender : class +#else + /// + /// Observes 4 observable properties with different types on the specified sender and applies a selector to the combined latest values. + /// + /// The type of the sender to monitor for property changes. + /// The return type of the selector. + /// The element type of observable property 1. + /// The element type of observable property 2. + /// The element type of observable property 3. + /// The element type of observable property 4. + /// The sender instance to observe for property changes. + /// An expression that selects observable property 1 to observe. + /// An expression that selects observable property 2 to observe. + /// An expression that selects observable property 3 to observe. + /// An expression that selects observable property 4 to observe. + /// A function that combines the latest values from all observables. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] + public static IObservable WhenAnyObservable( + this TSender sender, + Expression?>> obs1, + Expression?>> obs2, + Expression?>> obs3, + Expression?>> obs4, + Func selector, + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TSender : class +#endif + { + ArgumentExceptionHelper.ThrowIfNull(sender); + ArgumentExceptionHelper.ThrowIfNull(obs1); + ArgumentExceptionHelper.ThrowIfNull(obs2); + ArgumentExceptionHelper.ThrowIfNull(obs3); + ArgumentExceptionHelper.ThrowIfNull(obs4); + ArgumentExceptionHelper.ThrowIfNull(selector); + + var o1 = ObservableChainHelpers.SwitchLatest(sender, obs1); + var o2 = ObservableChainHelpers.SwitchLatest(sender, obs2); + var o3 = ObservableChainHelpers.SwitchLatest(sender, obs3); + var o4 = ObservableChainHelpers.SwitchLatest(sender, obs4); + return CombineLatestObservable.Create( + o1, + o2, + o3, + o4, + (v1, v2, v3, v4) => selector(v1, v2, v3, v4)); + } + +#if NET8_0_OR_GREATER + /// + /// Observes 5 observable properties with different types on the specified sender and applies a selector to the combined latest values. + /// + /// The type of the sender to monitor for property changes. + /// The return type of the selector. + /// The element type of observable property 1. + /// The element type of observable property 2. + /// The element type of observable property 3. + /// The element type of observable property 4. + /// The element type of observable property 5. + /// The sender instance to observe for property changes. + /// An expression that selects observable property 1 to observe. + /// An expression that selects observable property 2 to observe. + /// An expression that selects observable property 3 to observe. + /// An expression that selects observable property 4 to observe. + /// An expression that selects observable property 5 to observe. + /// A function that combines the latest values from all observables. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] + public static IObservable WhenAnyObservable( + this TSender sender, + Expression?>> obs1, + Expression?>> obs2, + Expression?>> obs3, + Expression?>> obs4, + Expression?>> obs5, + Func selector, + [CallerArgumentExpression("obs1")] string obs1Expression = "", + [CallerArgumentExpression("obs2")] string obs2Expression = "", + [CallerArgumentExpression("obs3")] string obs3Expression = "", + [CallerArgumentExpression("obs4")] string obs4Expression = "", + [CallerArgumentExpression("obs5")] string obs5Expression = "", + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TSender : class +#else + /// + /// Observes 5 observable properties with different types on the specified sender and applies a selector to the combined latest values. + /// + /// The type of the sender to monitor for property changes. + /// The return type of the selector. + /// The element type of observable property 1. + /// The element type of observable property 2. + /// The element type of observable property 3. + /// The element type of observable property 4. + /// The element type of observable property 5. + /// The sender instance to observe for property changes. + /// An expression that selects observable property 1 to observe. + /// An expression that selects observable property 2 to observe. + /// An expression that selects observable property 3 to observe. + /// An expression that selects observable property 4 to observe. + /// An expression that selects observable property 5 to observe. + /// A function that combines the latest values from all observables. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] + public static IObservable WhenAnyObservable( + this TSender sender, + Expression?>> obs1, + Expression?>> obs2, + Expression?>> obs3, + Expression?>> obs4, + Expression?>> obs5, + Func selector, + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TSender : class +#endif + { + ArgumentExceptionHelper.ThrowIfNull(sender); + ArgumentExceptionHelper.ThrowIfNull(obs1); + ArgumentExceptionHelper.ThrowIfNull(obs2); + ArgumentExceptionHelper.ThrowIfNull(obs3); + ArgumentExceptionHelper.ThrowIfNull(obs4); + ArgumentExceptionHelper.ThrowIfNull(obs5); + ArgumentExceptionHelper.ThrowIfNull(selector); + + var o1 = ObservableChainHelpers.SwitchLatest(sender, obs1); + var o2 = ObservableChainHelpers.SwitchLatest(sender, obs2); + var o3 = ObservableChainHelpers.SwitchLatest(sender, obs3); + var o4 = ObservableChainHelpers.SwitchLatest(sender, obs4); + var o5 = ObservableChainHelpers.SwitchLatest(sender, obs5); + return CombineLatestObservable.Create( + o1, + o2, + o3, + o4, + o5, + (v1, v2, v3, v4, v5) => selector(v1, v2, v3, v4, v5)); + } + +#if NET8_0_OR_GREATER + /// + /// Observes 6 observable properties with different types on the specified sender and applies a selector to the combined latest values. + /// + /// The type of the sender to monitor for property changes. + /// The return type of the selector. + /// The element type of observable property 1. + /// The element type of observable property 2. + /// The element type of observable property 3. + /// The element type of observable property 4. + /// The element type of observable property 5. + /// The element type of observable property 6. + /// The sender instance to observe for property changes. + /// An expression that selects observable property 1 to observe. + /// An expression that selects observable property 2 to observe. + /// An expression that selects observable property 3 to observe. + /// An expression that selects observable property 4 to observe. + /// An expression that selects observable property 5 to observe. + /// An expression that selects observable property 6 to observe. + /// A function that combines the latest values from all observables. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] + public static IObservable WhenAnyObservable( + this TSender sender, + Expression?>> obs1, + Expression?>> obs2, + Expression?>> obs3, + Expression?>> obs4, + Expression?>> obs5, + Expression?>> obs6, + Func selector, + [CallerArgumentExpression("obs1")] string obs1Expression = "", + [CallerArgumentExpression("obs2")] string obs2Expression = "", + [CallerArgumentExpression("obs3")] string obs3Expression = "", + [CallerArgumentExpression("obs4")] string obs4Expression = "", + [CallerArgumentExpression("obs5")] string obs5Expression = "", + [CallerArgumentExpression("obs6")] string obs6Expression = "", + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TSender : class +#else + /// + /// Observes 6 observable properties with different types on the specified sender and applies a selector to the combined latest values. + /// + /// The type of the sender to monitor for property changes. + /// The return type of the selector. + /// The element type of observable property 1. + /// The element type of observable property 2. + /// The element type of observable property 3. + /// The element type of observable property 4. + /// The element type of observable property 5. + /// The element type of observable property 6. + /// The sender instance to observe for property changes. + /// An expression that selects observable property 1 to observe. + /// An expression that selects observable property 2 to observe. + /// An expression that selects observable property 3 to observe. + /// An expression that selects observable property 4 to observe. + /// An expression that selects observable property 5 to observe. + /// An expression that selects observable property 6 to observe. + /// A function that combines the latest values from all observables. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] + public static IObservable WhenAnyObservable( + this TSender sender, + Expression?>> obs1, + Expression?>> obs2, + Expression?>> obs3, + Expression?>> obs4, + Expression?>> obs5, + Expression?>> obs6, + Func selector, + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TSender : class +#endif + { + ArgumentExceptionHelper.ThrowIfNull(sender); + ArgumentExceptionHelper.ThrowIfNull(obs1); + ArgumentExceptionHelper.ThrowIfNull(obs2); + ArgumentExceptionHelper.ThrowIfNull(obs3); + ArgumentExceptionHelper.ThrowIfNull(obs4); + ArgumentExceptionHelper.ThrowIfNull(obs5); + ArgumentExceptionHelper.ThrowIfNull(obs6); + ArgumentExceptionHelper.ThrowIfNull(selector); + + var o1 = ObservableChainHelpers.SwitchLatest(sender, obs1); + var o2 = ObservableChainHelpers.SwitchLatest(sender, obs2); + var o3 = ObservableChainHelpers.SwitchLatest(sender, obs3); + var o4 = ObservableChainHelpers.SwitchLatest(sender, obs4); + var o5 = ObservableChainHelpers.SwitchLatest(sender, obs5); + var o6 = ObservableChainHelpers.SwitchLatest(sender, obs6); + return CombineLatestObservable.Create( + o1, + o2, + o3, + o4, + o5, + o6, + (v1, v2, v3, v4, v5, v6) => selector(v1, v2, v3, v4, v5, v6)); + } + +#if NET8_0_OR_GREATER + /// + /// Observes 7 observable properties with different types on the specified sender and applies a selector to the combined latest values. + /// + /// The type of the sender to monitor for property changes. + /// The return type of the selector. + /// The element type of observable property 1. + /// The element type of observable property 2. + /// The element type of observable property 3. + /// The element type of observable property 4. + /// The element type of observable property 5. + /// The element type of observable property 6. + /// The element type of observable property 7. + /// The sender instance to observe for property changes. + /// An expression that selects observable property 1 to observe. + /// An expression that selects observable property 2 to observe. + /// An expression that selects observable property 3 to observe. + /// An expression that selects observable property 4 to observe. + /// An expression that selects observable property 5 to observe. + /// An expression that selects observable property 6 to observe. + /// An expression that selects observable property 7 to observe. + /// A function that combines the latest values from all observables. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] + public static IObservable WhenAnyObservable( + this TSender sender, + Expression?>> obs1, + Expression?>> obs2, + Expression?>> obs3, + Expression?>> obs4, + Expression?>> obs5, + Expression?>> obs6, + Expression?>> obs7, + Func selector, + [CallerArgumentExpression("obs1")] string obs1Expression = "", + [CallerArgumentExpression("obs2")] string obs2Expression = "", + [CallerArgumentExpression("obs3")] string obs3Expression = "", + [CallerArgumentExpression("obs4")] string obs4Expression = "", + [CallerArgumentExpression("obs5")] string obs5Expression = "", + [CallerArgumentExpression("obs6")] string obs6Expression = "", + [CallerArgumentExpression("obs7")] string obs7Expression = "", + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TSender : class +#else + /// + /// Observes 7 observable properties with different types on the specified sender and applies a selector to the combined latest values. + /// + /// The type of the sender to monitor for property changes. + /// The return type of the selector. + /// The element type of observable property 1. + /// The element type of observable property 2. + /// The element type of observable property 3. + /// The element type of observable property 4. + /// The element type of observable property 5. + /// The element type of observable property 6. + /// The element type of observable property 7. + /// The sender instance to observe for property changes. + /// An expression that selects observable property 1 to observe. + /// An expression that selects observable property 2 to observe. + /// An expression that selects observable property 3 to observe. + /// An expression that selects observable property 4 to observe. + /// An expression that selects observable property 5 to observe. + /// An expression that selects observable property 6 to observe. + /// An expression that selects observable property 7 to observe. + /// A function that combines the latest values from all observables. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] + [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] + public static IObservable WhenAnyObservable( + this TSender sender, + Expression?>> obs1, + Expression?>> obs2, + Expression?>> obs3, + Expression?>> obs4, + Expression?>> obs5, + Expression?>> obs6, + Expression?>> obs7, + Func selector, + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TSender : class +#endif + { + ArgumentExceptionHelper.ThrowIfNull(sender); + ArgumentExceptionHelper.ThrowIfNull(obs1); + ArgumentExceptionHelper.ThrowIfNull(obs2); + ArgumentExceptionHelper.ThrowIfNull(obs3); + ArgumentExceptionHelper.ThrowIfNull(obs4); + ArgumentExceptionHelper.ThrowIfNull(obs5); + ArgumentExceptionHelper.ThrowIfNull(obs6); + ArgumentExceptionHelper.ThrowIfNull(obs7); + ArgumentExceptionHelper.ThrowIfNull(selector); + + var o1 = ObservableChainHelpers.SwitchLatest(sender, obs1); + var o2 = ObservableChainHelpers.SwitchLatest(sender, obs2); + var o3 = ObservableChainHelpers.SwitchLatest(sender, obs3); + var o4 = ObservableChainHelpers.SwitchLatest(sender, obs4); + var o5 = ObservableChainHelpers.SwitchLatest(sender, obs5); + var o6 = ObservableChainHelpers.SwitchLatest(sender, obs6); + var o7 = ObservableChainHelpers.SwitchLatest(sender, obs7); + return CombineLatestObservable.Create( + o1, + o2, + o3, + o4, + o5, + o6, + o7, + (v1, v2, v3, v4, v5, v6, v7) => selector(v1, v2, v3, v4, v5, v6, v7)); + } + +#if NET8_0_OR_GREATER + /// + /// Observes 8 observable properties with different types on the specified sender and applies a selector to the combined latest values. + /// + /// The type of the sender to monitor for property changes. + /// The return type of the selector. + /// The element type of observable property 1. + /// The element type of observable property 2. + /// The element type of observable property 3. + /// The element type of observable property 4. + /// The element type of observable property 5. + /// The element type of observable property 6. + /// The element type of observable property 7. + /// The element type of observable property 8. + /// The sender instance to observe for property changes. + /// An expression that selects observable property 1 to observe. + /// An expression that selects observable property 2 to observe. + /// An expression that selects observable property 3 to observe. + /// An expression that selects observable property 4 to observe. + /// An expression that selects observable property 5 to observe. + /// An expression that selects observable property 6 to observe. + /// An expression that selects observable property 7 to observe. + /// An expression that selects observable property 8 to observe. + /// A function that combines the latest values from all observables. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] + public static IObservable WhenAnyObservable( + this TSender sender, + Expression?>> obs1, + Expression?>> obs2, + Expression?>> obs3, + Expression?>> obs4, + Expression?>> obs5, + Expression?>> obs6, + Expression?>> obs7, + Expression?>> obs8, + Func selector, + [CallerArgumentExpression("obs1")] string obs1Expression = "", + [CallerArgumentExpression("obs2")] string obs2Expression = "", + [CallerArgumentExpression("obs3")] string obs3Expression = "", + [CallerArgumentExpression("obs4")] string obs4Expression = "", + [CallerArgumentExpression("obs5")] string obs5Expression = "", + [CallerArgumentExpression("obs6")] string obs6Expression = "", + [CallerArgumentExpression("obs7")] string obs7Expression = "", + [CallerArgumentExpression("obs8")] string obs8Expression = "", + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TSender : class +#else + /// + /// Observes 8 observable properties with different types on the specified sender and applies a selector to the combined latest values. + /// + /// The type of the sender to monitor for property changes. + /// The return type of the selector. + /// The element type of observable property 1. + /// The element type of observable property 2. + /// The element type of observable property 3. + /// The element type of observable property 4. + /// The element type of observable property 5. + /// The element type of observable property 6. + /// The element type of observable property 7. + /// The element type of observable property 8. + /// The sender instance to observe for property changes. + /// An expression that selects observable property 1 to observe. + /// An expression that selects observable property 2 to observe. + /// An expression that selects observable property 3 to observe. + /// An expression that selects observable property 4 to observe. + /// An expression that selects observable property 5 to observe. + /// An expression that selects observable property 6 to observe. + /// An expression that selects observable property 7 to observe. + /// An expression that selects observable property 8 to observe. + /// A function that combines the latest values from all observables. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] + [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] + public static IObservable WhenAnyObservable( + this TSender sender, + Expression?>> obs1, + Expression?>> obs2, + Expression?>> obs3, + Expression?>> obs4, + Expression?>> obs5, + Expression?>> obs6, + Expression?>> obs7, + Expression?>> obs8, + Func selector, + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TSender : class +#endif + { + ArgumentExceptionHelper.ThrowIfNull(sender); + ArgumentExceptionHelper.ThrowIfNull(obs1); + ArgumentExceptionHelper.ThrowIfNull(obs2); + ArgumentExceptionHelper.ThrowIfNull(obs3); + ArgumentExceptionHelper.ThrowIfNull(obs4); + ArgumentExceptionHelper.ThrowIfNull(obs5); + ArgumentExceptionHelper.ThrowIfNull(obs6); + ArgumentExceptionHelper.ThrowIfNull(obs7); + ArgumentExceptionHelper.ThrowIfNull(obs8); + ArgumentExceptionHelper.ThrowIfNull(selector); + + var o1 = ObservableChainHelpers.SwitchLatest(sender, obs1); + var o2 = ObservableChainHelpers.SwitchLatest(sender, obs2); + var o3 = ObservableChainHelpers.SwitchLatest(sender, obs3); + var o4 = ObservableChainHelpers.SwitchLatest(sender, obs4); + var o5 = ObservableChainHelpers.SwitchLatest(sender, obs5); + var o6 = ObservableChainHelpers.SwitchLatest(sender, obs6); + var o7 = ObservableChainHelpers.SwitchLatest(sender, obs7); + var o8 = ObservableChainHelpers.SwitchLatest(sender, obs8); + return CombineLatestObservable.Create( + o1, + o2, + o3, + o4, + o5, + o6, + o7, + o8, + (v1, v2, v3, v4, v5, v6, v7, v8) => selector(v1, v2, v3, v4, v5, v6, v7, v8)); + } + +#if NET8_0_OR_GREATER + /// + /// Observes 9 observable properties with different types on the specified sender and applies a selector to the combined latest values. + /// + /// The type of the sender to monitor for property changes. + /// The return type of the selector. + /// The element type of observable property 1. + /// The element type of observable property 2. + /// The element type of observable property 3. + /// The element type of observable property 4. + /// The element type of observable property 5. + /// The element type of observable property 6. + /// The element type of observable property 7. + /// The element type of observable property 8. + /// The element type of observable property 9. + /// The sender instance to observe for property changes. + /// An expression that selects observable property 1 to observe. + /// An expression that selects observable property 2 to observe. + /// An expression that selects observable property 3 to observe. + /// An expression that selects observable property 4 to observe. + /// An expression that selects observable property 5 to observe. + /// An expression that selects observable property 6 to observe. + /// An expression that selects observable property 7 to observe. + /// An expression that selects observable property 8 to observe. + /// An expression that selects observable property 9 to observe. + /// A function that combines the latest values from all observables. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] + public static IObservable WhenAnyObservable( + this TSender sender, + Expression?>> obs1, + Expression?>> obs2, + Expression?>> obs3, + Expression?>> obs4, + Expression?>> obs5, + Expression?>> obs6, + Expression?>> obs7, + Expression?>> obs8, + Expression?>> obs9, + Func selector, + [CallerArgumentExpression("obs1")] string obs1Expression = "", + [CallerArgumentExpression("obs2")] string obs2Expression = "", + [CallerArgumentExpression("obs3")] string obs3Expression = "", + [CallerArgumentExpression("obs4")] string obs4Expression = "", + [CallerArgumentExpression("obs5")] string obs5Expression = "", + [CallerArgumentExpression("obs6")] string obs6Expression = "", + [CallerArgumentExpression("obs7")] string obs7Expression = "", + [CallerArgumentExpression("obs8")] string obs8Expression = "", + [CallerArgumentExpression("obs9")] string obs9Expression = "", + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TSender : class +#else + /// + /// Observes 9 observable properties with different types on the specified sender and applies a selector to the combined latest values. + /// + /// The type of the sender to monitor for property changes. + /// The return type of the selector. + /// The element type of observable property 1. + /// The element type of observable property 2. + /// The element type of observable property 3. + /// The element type of observable property 4. + /// The element type of observable property 5. + /// The element type of observable property 6. + /// The element type of observable property 7. + /// The element type of observable property 8. + /// The element type of observable property 9. + /// The sender instance to observe for property changes. + /// An expression that selects observable property 1 to observe. + /// An expression that selects observable property 2 to observe. + /// An expression that selects observable property 3 to observe. + /// An expression that selects observable property 4 to observe. + /// An expression that selects observable property 5 to observe. + /// An expression that selects observable property 6 to observe. + /// An expression that selects observable property 7 to observe. + /// An expression that selects observable property 8 to observe. + /// An expression that selects observable property 9 to observe. + /// A function that combines the latest values from all observables. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] + [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] + public static IObservable WhenAnyObservable( + this TSender sender, + Expression?>> obs1, + Expression?>> obs2, + Expression?>> obs3, + Expression?>> obs4, + Expression?>> obs5, + Expression?>> obs6, + Expression?>> obs7, + Expression?>> obs8, + Expression?>> obs9, + Func selector, + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TSender : class +#endif + { + ArgumentExceptionHelper.ThrowIfNull(sender); + ArgumentExceptionHelper.ThrowIfNull(obs1); + ArgumentExceptionHelper.ThrowIfNull(obs2); + ArgumentExceptionHelper.ThrowIfNull(obs3); + ArgumentExceptionHelper.ThrowIfNull(obs4); + ArgumentExceptionHelper.ThrowIfNull(obs5); + ArgumentExceptionHelper.ThrowIfNull(obs6); + ArgumentExceptionHelper.ThrowIfNull(obs7); + ArgumentExceptionHelper.ThrowIfNull(obs8); + ArgumentExceptionHelper.ThrowIfNull(obs9); + ArgumentExceptionHelper.ThrowIfNull(selector); + + var o1 = ObservableChainHelpers.SwitchLatest(sender, obs1); + var o2 = ObservableChainHelpers.SwitchLatest(sender, obs2); + var o3 = ObservableChainHelpers.SwitchLatest(sender, obs3); + var o4 = ObservableChainHelpers.SwitchLatest(sender, obs4); + var o5 = ObservableChainHelpers.SwitchLatest(sender, obs5); + var o6 = ObservableChainHelpers.SwitchLatest(sender, obs6); + var o7 = ObservableChainHelpers.SwitchLatest(sender, obs7); + var o8 = ObservableChainHelpers.SwitchLatest(sender, obs8); + var o9 = ObservableChainHelpers.SwitchLatest(sender, obs9); + return CombineLatestObservable.Create( + o1, + o2, + o3, + o4, + o5, + o6, + o7, + o8, + o9, + (v1, v2, v3, v4, v5, v6, v7, v8, v9) => selector(v1, v2, v3, v4, v5, v6, v7, v8, v9)); + } + +#if NET8_0_OR_GREATER + /// + /// Observes 10 observable properties with different types on the specified sender and applies a selector to the combined latest values. + /// + /// The type of the sender to monitor for property changes. + /// The return type of the selector. + /// The element type of observable property 1. + /// The element type of observable property 2. + /// The element type of observable property 3. + /// The element type of observable property 4. + /// The element type of observable property 5. + /// The element type of observable property 6. + /// The element type of observable property 7. + /// The element type of observable property 8. + /// The element type of observable property 9. + /// The element type of observable property 10. + /// The sender instance to observe for property changes. + /// An expression that selects observable property 1 to observe. + /// An expression that selects observable property 2 to observe. + /// An expression that selects observable property 3 to observe. + /// An expression that selects observable property 4 to observe. + /// An expression that selects observable property 5 to observe. + /// An expression that selects observable property 6 to observe. + /// An expression that selects observable property 7 to observe. + /// An expression that selects observable property 8 to observe. + /// An expression that selects observable property 9 to observe. + /// An expression that selects observable property 10 to observe. + /// A function that combines the latest values from all observables. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] + public static IObservable WhenAnyObservable( + this TSender sender, + Expression?>> obs1, + Expression?>> obs2, + Expression?>> obs3, + Expression?>> obs4, + Expression?>> obs5, + Expression?>> obs6, + Expression?>> obs7, + Expression?>> obs8, + Expression?>> obs9, + Expression?>> obs10, + Func selector, + [CallerArgumentExpression("obs1")] string obs1Expression = "", + [CallerArgumentExpression("obs2")] string obs2Expression = "", + [CallerArgumentExpression("obs3")] string obs3Expression = "", + [CallerArgumentExpression("obs4")] string obs4Expression = "", + [CallerArgumentExpression("obs5")] string obs5Expression = "", + [CallerArgumentExpression("obs6")] string obs6Expression = "", + [CallerArgumentExpression("obs7")] string obs7Expression = "", + [CallerArgumentExpression("obs8")] string obs8Expression = "", + [CallerArgumentExpression("obs9")] string obs9Expression = "", + [CallerArgumentExpression("obs10")] string obs10Expression = "", + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TSender : class +#else + /// + /// Observes 10 observable properties with different types on the specified sender and applies a selector to the combined latest values. + /// + /// The type of the sender to monitor for property changes. + /// The return type of the selector. + /// The element type of observable property 1. + /// The element type of observable property 2. + /// The element type of observable property 3. + /// The element type of observable property 4. + /// The element type of observable property 5. + /// The element type of observable property 6. + /// The element type of observable property 7. + /// The element type of observable property 8. + /// The element type of observable property 9. + /// The element type of observable property 10. + /// The sender instance to observe for property changes. + /// An expression that selects observable property 1 to observe. + /// An expression that selects observable property 2 to observe. + /// An expression that selects observable property 3 to observe. + /// An expression that selects observable property 4 to observe. + /// An expression that selects observable property 5 to observe. + /// An expression that selects observable property 6 to observe. + /// An expression that selects observable property 7 to observe. + /// An expression that selects observable property 8 to observe. + /// An expression that selects observable property 9 to observe. + /// An expression that selects observable property 10 to observe. + /// A function that combines the latest values from all observables. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] + [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] + public static IObservable WhenAnyObservable( + this TSender sender, + Expression?>> obs1, + Expression?>> obs2, + Expression?>> obs3, + Expression?>> obs4, + Expression?>> obs5, + Expression?>> obs6, + Expression?>> obs7, + Expression?>> obs8, + Expression?>> obs9, + Expression?>> obs10, + Func selector, + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TSender : class +#endif + { + ArgumentExceptionHelper.ThrowIfNull(sender); + ArgumentExceptionHelper.ThrowIfNull(obs1); + ArgumentExceptionHelper.ThrowIfNull(obs2); + ArgumentExceptionHelper.ThrowIfNull(obs3); + ArgumentExceptionHelper.ThrowIfNull(obs4); + ArgumentExceptionHelper.ThrowIfNull(obs5); + ArgumentExceptionHelper.ThrowIfNull(obs6); + ArgumentExceptionHelper.ThrowIfNull(obs7); + ArgumentExceptionHelper.ThrowIfNull(obs8); + ArgumentExceptionHelper.ThrowIfNull(obs9); + ArgumentExceptionHelper.ThrowIfNull(obs10); + ArgumentExceptionHelper.ThrowIfNull(selector); + + var o1 = ObservableChainHelpers.SwitchLatest(sender, obs1); + var o2 = ObservableChainHelpers.SwitchLatest(sender, obs2); + var o3 = ObservableChainHelpers.SwitchLatest(sender, obs3); + var o4 = ObservableChainHelpers.SwitchLatest(sender, obs4); + var o5 = ObservableChainHelpers.SwitchLatest(sender, obs5); + var o6 = ObservableChainHelpers.SwitchLatest(sender, obs6); + var o7 = ObservableChainHelpers.SwitchLatest(sender, obs7); + var o8 = ObservableChainHelpers.SwitchLatest(sender, obs8); + var o9 = ObservableChainHelpers.SwitchLatest(sender, obs9); + var o10 = ObservableChainHelpers.SwitchLatest(sender, obs10); + return CombineLatestObservable.Create( + o1, + o2, + o3, + o4, + o5, + o6, + o7, + o8, + o9, + o10, + selector); + } + +#if NET8_0_OR_GREATER + /// + /// Observes 11 observable properties with different types on the specified sender and applies a selector to the combined latest values. + /// + /// The type of the sender to monitor for property changes. + /// The return type of the selector. + /// The element type of observable property 1. + /// The element type of observable property 2. + /// The element type of observable property 3. + /// The element type of observable property 4. + /// The element type of observable property 5. + /// The element type of observable property 6. + /// The element type of observable property 7. + /// The element type of observable property 8. + /// The element type of observable property 9. + /// The element type of observable property 10. + /// The element type of observable property 11. + /// The sender instance to observe for property changes. + /// An expression that selects observable property 1 to observe. + /// An expression that selects observable property 2 to observe. + /// An expression that selects observable property 3 to observe. + /// An expression that selects observable property 4 to observe. + /// An expression that selects observable property 5 to observe. + /// An expression that selects observable property 6 to observe. + /// An expression that selects observable property 7 to observe. + /// An expression that selects observable property 8 to observe. + /// An expression that selects observable property 9 to observe. + /// An expression that selects observable property 10 to observe. + /// An expression that selects observable property 11 to observe. + /// A function that combines the latest values from all observables. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] + public static IObservable WhenAnyObservable( + this TSender sender, + Expression?>> obs1, + Expression?>> obs2, + Expression?>> obs3, + Expression?>> obs4, + Expression?>> obs5, + Expression?>> obs6, + Expression?>> obs7, + Expression?>> obs8, + Expression?>> obs9, + Expression?>> obs10, + Expression?>> obs11, + Func selector, + [CallerArgumentExpression("obs1")] string obs1Expression = "", + [CallerArgumentExpression("obs2")] string obs2Expression = "", + [CallerArgumentExpression("obs3")] string obs3Expression = "", + [CallerArgumentExpression("obs4")] string obs4Expression = "", + [CallerArgumentExpression("obs5")] string obs5Expression = "", + [CallerArgumentExpression("obs6")] string obs6Expression = "", + [CallerArgumentExpression("obs7")] string obs7Expression = "", + [CallerArgumentExpression("obs8")] string obs8Expression = "", + [CallerArgumentExpression("obs9")] string obs9Expression = "", + [CallerArgumentExpression("obs10")] string obs10Expression = "", + [CallerArgumentExpression("obs11")] string obs11Expression = "", + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TSender : class +#else + /// + /// Observes 11 observable properties with different types on the specified sender and applies a selector to the combined latest values. + /// + /// The type of the sender to monitor for property changes. + /// The return type of the selector. + /// The element type of observable property 1. + /// The element type of observable property 2. + /// The element type of observable property 3. + /// The element type of observable property 4. + /// The element type of observable property 5. + /// The element type of observable property 6. + /// The element type of observable property 7. + /// The element type of observable property 8. + /// The element type of observable property 9. + /// The element type of observable property 10. + /// The element type of observable property 11. + /// The sender instance to observe for property changes. + /// An expression that selects observable property 1 to observe. + /// An expression that selects observable property 2 to observe. + /// An expression that selects observable property 3 to observe. + /// An expression that selects observable property 4 to observe. + /// An expression that selects observable property 5 to observe. + /// An expression that selects observable property 6 to observe. + /// An expression that selects observable property 7 to observe. + /// An expression that selects observable property 8 to observe. + /// An expression that selects observable property 9 to observe. + /// An expression that selects observable property 10 to observe. + /// An expression that selects observable property 11 to observe. + /// A function that combines the latest values from all observables. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] + [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] + public static IObservable WhenAnyObservable( + this TSender sender, + Expression?>> obs1, + Expression?>> obs2, + Expression?>> obs3, + Expression?>> obs4, + Expression?>> obs5, + Expression?>> obs6, + Expression?>> obs7, + Expression?>> obs8, + Expression?>> obs9, + Expression?>> obs10, + Expression?>> obs11, + Func selector, + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TSender : class +#endif + { + ArgumentExceptionHelper.ThrowIfNull(sender); + ArgumentExceptionHelper.ThrowIfNull(obs1); + ArgumentExceptionHelper.ThrowIfNull(obs2); + ArgumentExceptionHelper.ThrowIfNull(obs3); + ArgumentExceptionHelper.ThrowIfNull(obs4); + ArgumentExceptionHelper.ThrowIfNull(obs5); + ArgumentExceptionHelper.ThrowIfNull(obs6); + ArgumentExceptionHelper.ThrowIfNull(obs7); + ArgumentExceptionHelper.ThrowIfNull(obs8); + ArgumentExceptionHelper.ThrowIfNull(obs9); + ArgumentExceptionHelper.ThrowIfNull(obs10); + ArgumentExceptionHelper.ThrowIfNull(obs11); + ArgumentExceptionHelper.ThrowIfNull(selector); + + var o1 = ObservableChainHelpers.SwitchLatest(sender, obs1); + var o2 = ObservableChainHelpers.SwitchLatest(sender, obs2); + var o3 = ObservableChainHelpers.SwitchLatest(sender, obs3); + var o4 = ObservableChainHelpers.SwitchLatest(sender, obs4); + var o5 = ObservableChainHelpers.SwitchLatest(sender, obs5); + var o6 = ObservableChainHelpers.SwitchLatest(sender, obs6); + var o7 = ObservableChainHelpers.SwitchLatest(sender, obs7); + var o8 = ObservableChainHelpers.SwitchLatest(sender, obs8); + var o9 = ObservableChainHelpers.SwitchLatest(sender, obs9); + var o10 = ObservableChainHelpers.SwitchLatest(sender, obs10); + var o11 = ObservableChainHelpers.SwitchLatest(sender, obs11); + return CombineLatestObservable.Create( + o1, + o2, + o3, + o4, + o5, + o6, + o7, + o8, + o9, + o10, + o11, + selector); + } + +#if NET8_0_OR_GREATER + /// + /// Observes 12 observable properties with different types on the specified sender and applies a selector to the combined latest values. + /// + /// The type of the sender to monitor for property changes. + /// The return type of the selector. + /// The element type of observable property 1. + /// The element type of observable property 2. + /// The element type of observable property 3. + /// The element type of observable property 4. + /// The element type of observable property 5. + /// The element type of observable property 6. + /// The element type of observable property 7. + /// The element type of observable property 8. + /// The element type of observable property 9. + /// The element type of observable property 10. + /// The element type of observable property 11. + /// The element type of observable property 12. + /// The sender instance to observe for property changes. + /// An expression that selects observable property 1 to observe. + /// An expression that selects observable property 2 to observe. + /// An expression that selects observable property 3 to observe. + /// An expression that selects observable property 4 to observe. + /// An expression that selects observable property 5 to observe. + /// An expression that selects observable property 6 to observe. + /// An expression that selects observable property 7 to observe. + /// An expression that selects observable property 8 to observe. + /// An expression that selects observable property 9 to observe. + /// An expression that selects observable property 10 to observe. + /// An expression that selects observable property 11 to observe. + /// An expression that selects observable property 12 to observe. + /// A function that combines the latest values from all observables. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The caller argument expression for . Auto-populated by the compiler. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] + public static IObservable WhenAnyObservable( + this TSender sender, + Expression?>> obs1, + Expression?>> obs2, + Expression?>> obs3, + Expression?>> obs4, + Expression?>> obs5, + Expression?>> obs6, + Expression?>> obs7, + Expression?>> obs8, + Expression?>> obs9, + Expression?>> obs10, + Expression?>> obs11, + Expression?>> obs12, + Func selector, + [CallerArgumentExpression("obs1")] string obs1Expression = "", + [CallerArgumentExpression("obs2")] string obs2Expression = "", + [CallerArgumentExpression("obs3")] string obs3Expression = "", + [CallerArgumentExpression("obs4")] string obs4Expression = "", + [CallerArgumentExpression("obs5")] string obs5Expression = "", + [CallerArgumentExpression("obs6")] string obs6Expression = "", + [CallerArgumentExpression("obs7")] string obs7Expression = "", + [CallerArgumentExpression("obs8")] string obs8Expression = "", + [CallerArgumentExpression("obs9")] string obs9Expression = "", + [CallerArgumentExpression("obs10")] string obs10Expression = "", + [CallerArgumentExpression("obs11")] string obs11Expression = "", + [CallerArgumentExpression("obs12")] string obs12Expression = "", + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TSender : class +#else + /// + /// Observes 12 observable properties with different types on the specified sender and applies a selector to the combined latest values. + /// + /// The type of the sender to monitor for property changes. + /// The return type of the selector. + /// The element type of observable property 1. + /// The element type of observable property 2. + /// The element type of observable property 3. + /// The element type of observable property 4. + /// The element type of observable property 5. + /// The element type of observable property 6. + /// The element type of observable property 7. + /// The element type of observable property 8. + /// The element type of observable property 9. + /// The element type of observable property 10. + /// The element type of observable property 11. + /// The element type of observable property 12. + /// The sender instance to observe for property changes. + /// An expression that selects observable property 1 to observe. + /// An expression that selects observable property 2 to observe. + /// An expression that selects observable property 3 to observe. + /// An expression that selects observable property 4 to observe. + /// An expression that selects observable property 5 to observe. + /// An expression that selects observable property 6 to observe. + /// An expression that selects observable property 7 to observe. + /// An expression that selects observable property 8 to observe. + /// An expression that selects observable property 9 to observe. + /// An expression that selects observable property 10 to observe. + /// An expression that selects observable property 11 to observe. + /// An expression that selects observable property 12 to observe. + /// A function that combines the latest values from all observables. + /// The source file path of the caller. Auto-populated by the compiler. + /// The source line number of the caller. Auto-populated by the compiler. + /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] + [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] + public static IObservable WhenAnyObservable( + this TSender sender, + Expression?>> obs1, + Expression?>> obs2, + Expression?>> obs3, + Expression?>> obs4, + Expression?>> obs5, + Expression?>> obs6, + Expression?>> obs7, + Expression?>> obs8, + Expression?>> obs9, + Expression?>> obs10, + Expression?>> obs11, + Expression?>> obs12, + Func selector, + [CallerFilePath] string callerFilePath = "", + [CallerLineNumber] int callerLineNumber = 0) + where TSender : class +#endif + { + ArgumentExceptionHelper.ThrowIfNull(sender); + ArgumentExceptionHelper.ThrowIfNull(obs1); + ArgumentExceptionHelper.ThrowIfNull(obs2); + ArgumentExceptionHelper.ThrowIfNull(obs3); + ArgumentExceptionHelper.ThrowIfNull(obs4); + ArgumentExceptionHelper.ThrowIfNull(obs5); + ArgumentExceptionHelper.ThrowIfNull(obs6); + ArgumentExceptionHelper.ThrowIfNull(obs7); + ArgumentExceptionHelper.ThrowIfNull(obs8); + ArgumentExceptionHelper.ThrowIfNull(obs9); + ArgumentExceptionHelper.ThrowIfNull(obs10); + ArgumentExceptionHelper.ThrowIfNull(obs11); + ArgumentExceptionHelper.ThrowIfNull(obs12); + ArgumentExceptionHelper.ThrowIfNull(selector); + + var o1 = ObservableChainHelpers.SwitchLatest(sender, obs1); + var o2 = ObservableChainHelpers.SwitchLatest(sender, obs2); + var o3 = ObservableChainHelpers.SwitchLatest(sender, obs3); + var o4 = ObservableChainHelpers.SwitchLatest(sender, obs4); + var o5 = ObservableChainHelpers.SwitchLatest(sender, obs5); + var o6 = ObservableChainHelpers.SwitchLatest(sender, obs6); + var o7 = ObservableChainHelpers.SwitchLatest(sender, obs7); + var o8 = ObservableChainHelpers.SwitchLatest(sender, obs8); + var o9 = ObservableChainHelpers.SwitchLatest(sender, obs9); + var o10 = ObservableChainHelpers.SwitchLatest(sender, obs10); + var o11 = ObservableChainHelpers.SwitchLatest(sender, obs11); + var o12 = ObservableChainHelpers.SwitchLatest(sender, obs12); + return CombineLatestObservable.Create( + o1, + o2, + o3, + o4, + o5, + o6, + o7, + o8, + o9, + o10, + o11, + o12, + selector); + } +} diff --git a/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenAnyObservable.cs b/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenAnyObservable.cs index c5425dc..be961af 100644 --- a/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenAnyObservable.cs +++ b/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenAnyObservable.cs @@ -2,7 +2,9 @@ // ReactiveUI Association Incorporated licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System.Diagnostics.CodeAnalysis; using ReactiveUI.Binding.ObservableForProperty; + using ReactiveUI.Binding.Observables; namespace ReactiveUI.Binding; @@ -14,9 +16,7 @@ namespace ReactiveUI.Binding; public static partial class ReactiveUIBindingExtensions { #if NET8_0_OR_GREATER - /// - /// Observes 1 observable property on the specified sender and switches to the latest observable. - /// + /// Observes 1 observable property on the specified sender and switches to the latest observable. /// The type of the sender to monitor for property changes. /// The element type of the observed observables. /// The sender instance to observe for property changes. @@ -34,9 +34,7 @@ public static IObservable WhenAnyObservable( [CallerLineNumber] int callerLineNumber = 0) where TSender : class #else - /// - /// Observes 1 observable property on the specified sender and switches to the latest observable. - /// + /// Observes 1 observable property on the specified sender and switches to the latest observable. /// The type of the sender to monitor for property changes. /// The element type of the observed observables. /// The sender instance to observe for property changes. @@ -59,14 +57,12 @@ public static IObservable WhenAnyObservable( return sender.SubscribeToExpressionChain?>( obs1.Body, skipInitial: false) - .Select(x => x.Value ?? EmptyObservable.Instance) + .Select(static x => x.Value ?? EmptyObservable.Instance) .Switch(); } #if NET8_0_OR_GREATER - /// - /// Observes 2 observable properties on the specified sender and merges the switched observables. - /// + /// Observes 2 observable properties on the specified sender and merges the switched observables. /// The type of the sender to monitor for property changes. /// The element type of the observed observables. /// The sender instance to observe for property changes. @@ -88,9 +84,7 @@ public static IObservable WhenAnyObservable( [CallerLineNumber] int callerLineNumber = 0) where TSender : class #else - /// - /// Observes 2 observable properties on the specified sender and merges the switched observables. - /// + /// Observes 2 observable properties on the specified sender and merges the switched observables. /// The type of the sender to monitor for property changes. /// The element type of the observed observables. /// The sender instance to observe for property changes. @@ -119,9 +113,7 @@ public static IObservable WhenAnyObservable( } #if NET8_0_OR_GREATER - /// - /// Observes 3 observable properties on the specified sender and merges the switched observables. - /// + /// Observes 3 observable properties on the specified sender and merges the switched observables. /// The type of the sender to monitor for property changes. /// The element type of the observed observables. /// The sender instance to observe for property changes. @@ -134,6 +126,7 @@ public static IObservable WhenAnyObservable( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits values from the merged observed observables. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAnyObservable( this TSender sender, @@ -147,9 +140,7 @@ public static IObservable WhenAnyObservable( [CallerLineNumber] int callerLineNumber = 0) where TSender : class #else - /// - /// Observes 3 observable properties on the specified sender and merges the switched observables. - /// + /// Observes 3 observable properties on the specified sender and merges the switched observables. /// The type of the sender to monitor for property changes. /// The element type of the observed observables. /// The sender instance to observe for property changes. @@ -182,9 +173,7 @@ public static IObservable WhenAnyObservable( } #if NET8_0_OR_GREATER - /// - /// Observes 4 observable properties on the specified sender and merges the switched observables. - /// + /// Observes 4 observable properties on the specified sender and merges the switched observables. /// The type of the sender to monitor for property changes. /// The element type of the observed observables. /// The sender instance to observe for property changes. @@ -199,6 +188,7 @@ public static IObservable WhenAnyObservable( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits values from the merged observed observables. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAnyObservable( this TSender sender, @@ -214,9 +204,7 @@ public static IObservable WhenAnyObservable( [CallerLineNumber] int callerLineNumber = 0) where TSender : class #else - /// - /// Observes 4 observable properties on the specified sender and merges the switched observables. - /// + /// Observes 4 observable properties on the specified sender and merges the switched observables. /// The type of the sender to monitor for property changes. /// The element type of the observed observables. /// The sender instance to observe for property changes. @@ -253,9 +241,7 @@ public static IObservable WhenAnyObservable( } #if NET8_0_OR_GREATER - /// - /// Observes 5 observable properties on the specified sender and merges the switched observables. - /// + /// Observes 5 observable properties on the specified sender and merges the switched observables. /// The type of the sender to monitor for property changes. /// The element type of the observed observables. /// The sender instance to observe for property changes. @@ -272,6 +258,7 @@ public static IObservable WhenAnyObservable( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits values from the merged observed observables. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAnyObservable( this TSender sender, @@ -289,9 +276,7 @@ public static IObservable WhenAnyObservable( [CallerLineNumber] int callerLineNumber = 0) where TSender : class #else - /// - /// Observes 5 observable properties on the specified sender and merges the switched observables. - /// + /// Observes 5 observable properties on the specified sender and merges the switched observables. /// The type of the sender to monitor for property changes. /// The element type of the observed observables. /// The sender instance to observe for property changes. @@ -303,6 +288,7 @@ public static IObservable WhenAnyObservable( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits values from the merged observed observables. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAnyObservable( this TSender sender, @@ -332,9 +318,7 @@ public static IObservable WhenAnyObservable( } #if NET8_0_OR_GREATER - /// - /// Observes 6 observable properties on the specified sender and merges the switched observables. - /// + /// Observes 6 observable properties on the specified sender and merges the switched observables. /// The type of the sender to monitor for property changes. /// The element type of the observed observables. /// The sender instance to observe for property changes. @@ -353,6 +337,8 @@ public static IObservable WhenAnyObservable( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits values from the merged observed observables. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAnyObservable( this TSender sender, @@ -372,9 +358,7 @@ public static IObservable WhenAnyObservable( [CallerLineNumber] int callerLineNumber = 0) where TSender : class #else - /// - /// Observes 6 observable properties on the specified sender and merges the switched observables. - /// + /// Observes 6 observable properties on the specified sender and merges the switched observables. /// The type of the sender to monitor for property changes. /// The element type of the observed observables. /// The sender instance to observe for property changes. @@ -387,6 +371,7 @@ public static IObservable WhenAnyObservable( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits values from the merged observed observables. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAnyObservable( this TSender sender, @@ -419,9 +404,7 @@ public static IObservable WhenAnyObservable( } #if NET8_0_OR_GREATER - /// - /// Observes 7 observable properties on the specified sender and merges the switched observables. - /// + /// Observes 7 observable properties on the specified sender and merges the switched observables. /// The type of the sender to monitor for property changes. /// The element type of the observed observables. /// The sender instance to observe for property changes. @@ -442,6 +425,8 @@ public static IObservable WhenAnyObservable( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits values from the merged observed observables. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAnyObservable( this TSender sender, @@ -463,9 +448,7 @@ public static IObservable WhenAnyObservable( [CallerLineNumber] int callerLineNumber = 0) where TSender : class #else - /// - /// Observes 7 observable properties on the specified sender and merges the switched observables. - /// + /// Observes 7 observable properties on the specified sender and merges the switched observables. /// The type of the sender to monitor for property changes. /// The element type of the observed observables. /// The sender instance to observe for property changes. @@ -479,6 +462,7 @@ public static IObservable WhenAnyObservable( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits values from the merged observed observables. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAnyObservable( this TSender sender, @@ -514,9 +498,7 @@ public static IObservable WhenAnyObservable( } #if NET8_0_OR_GREATER - /// - /// Observes 8 observable properties on the specified sender and merges the switched observables. - /// + /// Observes 8 observable properties on the specified sender and merges the switched observables. /// The type of the sender to monitor for property changes. /// The element type of the observed observables. /// The sender instance to observe for property changes. @@ -539,6 +521,8 @@ public static IObservable WhenAnyObservable( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits values from the merged observed observables. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAnyObservable( this TSender sender, @@ -562,9 +546,7 @@ public static IObservable WhenAnyObservable( [CallerLineNumber] int callerLineNumber = 0) where TSender : class #else - /// - /// Observes 8 observable properties on the specified sender and merges the switched observables. - /// + /// Observes 8 observable properties on the specified sender and merges the switched observables. /// The type of the sender to monitor for property changes. /// The element type of the observed observables. /// The sender instance to observe for property changes. @@ -579,6 +561,7 @@ public static IObservable WhenAnyObservable( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits values from the merged observed observables. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAnyObservable( this TSender sender, @@ -617,9 +600,7 @@ public static IObservable WhenAnyObservable( } #if NET8_0_OR_GREATER - /// - /// Observes 9 observable properties on the specified sender and merges the switched observables. - /// + /// Observes 9 observable properties on the specified sender and merges the switched observables. /// The type of the sender to monitor for property changes. /// The element type of the observed observables. /// The sender instance to observe for property changes. @@ -644,6 +625,8 @@ public static IObservable WhenAnyObservable( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits values from the merged observed observables. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAnyObservable( this TSender sender, @@ -669,9 +652,7 @@ public static IObservable WhenAnyObservable( [CallerLineNumber] int callerLineNumber = 0) where TSender : class #else - /// - /// Observes 9 observable properties on the specified sender and merges the switched observables. - /// + /// Observes 9 observable properties on the specified sender and merges the switched observables. /// The type of the sender to monitor for property changes. /// The element type of the observed observables. /// The sender instance to observe for property changes. @@ -687,6 +668,7 @@ public static IObservable WhenAnyObservable( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits values from the merged observed observables. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAnyObservable( this TSender sender, @@ -728,9 +710,7 @@ public static IObservable WhenAnyObservable( } #if NET8_0_OR_GREATER - /// - /// Observes 10 observable properties on the specified sender and merges the switched observables. - /// + /// Observes 10 observable properties on the specified sender and merges the switched observables. /// The type of the sender to monitor for property changes. /// The element type of the observed observables. /// The sender instance to observe for property changes. @@ -757,6 +737,8 @@ public static IObservable WhenAnyObservable( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits values from the merged observed observables. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAnyObservable( this TSender sender, @@ -784,9 +766,7 @@ public static IObservable WhenAnyObservable( [CallerLineNumber] int callerLineNumber = 0) where TSender : class #else - /// - /// Observes 10 observable properties on the specified sender and merges the switched observables. - /// + /// Observes 10 observable properties on the specified sender and merges the switched observables. /// The type of the sender to monitor for property changes. /// The element type of the observed observables. /// The sender instance to observe for property changes. @@ -803,6 +783,7 @@ public static IObservable WhenAnyObservable( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits values from the merged observed observables. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAnyObservable( this TSender sender, @@ -847,9 +828,7 @@ public static IObservable WhenAnyObservable( } #if NET8_0_OR_GREATER - /// - /// Observes 11 observable properties on the specified sender and merges the switched observables. - /// + /// Observes 11 observable properties on the specified sender and merges the switched observables. /// The type of the sender to monitor for property changes. /// The element type of the observed observables. /// The sender instance to observe for property changes. @@ -878,6 +857,8 @@ public static IObservable WhenAnyObservable( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits values from the merged observed observables. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAnyObservable( this TSender sender, @@ -907,9 +888,7 @@ public static IObservable WhenAnyObservable( [CallerLineNumber] int callerLineNumber = 0) where TSender : class #else - /// - /// Observes 11 observable properties on the specified sender and merges the switched observables. - /// + /// Observes 11 observable properties on the specified sender and merges the switched observables. /// The type of the sender to monitor for property changes. /// The element type of the observed observables. /// The sender instance to observe for property changes. @@ -927,6 +906,7 @@ public static IObservable WhenAnyObservable( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits values from the merged observed observables. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAnyObservable( this TSender sender, @@ -974,9 +954,7 @@ public static IObservable WhenAnyObservable( } #if NET8_0_OR_GREATER - /// - /// Observes 12 observable properties on the specified sender and merges the switched observables. - /// + /// Observes 12 observable properties on the specified sender and merges the switched observables. /// The type of the sender to monitor for property changes. /// The element type of the observed observables. /// The sender instance to observe for property changes. @@ -1007,6 +985,8 @@ public static IObservable WhenAnyObservable( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits values from the merged observed observables. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAnyObservable( this TSender sender, @@ -1038,9 +1018,7 @@ public static IObservable WhenAnyObservable( [CallerLineNumber] int callerLineNumber = 0) where TSender : class #else - /// - /// Observes 12 observable properties on the specified sender and merges the switched observables. - /// + /// Observes 12 observable properties on the specified sender and merges the switched observables. /// The type of the sender to monitor for property changes. /// The element type of the observed observables. /// The sender instance to observe for property changes. @@ -1059,6 +1037,7 @@ public static IObservable WhenAnyObservable( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits values from the merged observed observables. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAnyObservable( this TSender sender, @@ -1125,6 +1104,7 @@ public static IObservable WhenAnyObservable( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence of selector results. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] public static IObservable WhenAnyObservable( this TSender sender, @@ -1174,1279 +1154,4 @@ public static IObservable WhenAnyObservable( o2, (v1, v2) => selector(v1, v2)); } - -#if NET8_0_OR_GREATER - /// - /// Observes 3 observable properties with different types on the specified sender and applies a selector to the combined latest values. - /// - /// The type of the sender to monitor for property changes. - /// The return type of the selector. - /// The element type of observable property 1. - /// The element type of observable property 2. - /// The element type of observable property 3. - /// The sender instance to observe for property changes. - /// An expression that selects observable property 1 to observe. - /// An expression that selects observable property 2 to observe. - /// An expression that selects observable property 3 to observe. - /// A function that combines the latest values from all observables. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// An observable sequence of selector results. - [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] - public static IObservable WhenAnyObservable( - this TSender sender, - Expression?>> obs1, - Expression?>> obs2, - Expression?>> obs3, - Func selector, - [CallerArgumentExpression("obs1")] string obs1Expression = "", - [CallerArgumentExpression("obs2")] string obs2Expression = "", - [CallerArgumentExpression("obs3")] string obs3Expression = "", - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSender : class -#else - /// - /// Observes 3 observable properties with different types on the specified sender and applies a selector to the combined latest values. - /// - /// The type of the sender to monitor for property changes. - /// The return type of the selector. - /// The element type of observable property 1. - /// The element type of observable property 2. - /// The element type of observable property 3. - /// The sender instance to observe for property changes. - /// An expression that selects observable property 1 to observe. - /// An expression that selects observable property 2 to observe. - /// An expression that selects observable property 3 to observe. - /// A function that combines the latest values from all observables. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// An observable sequence of selector results. - [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] - public static IObservable WhenAnyObservable( - this TSender sender, - Expression?>> obs1, - Expression?>> obs2, - Expression?>> obs3, - Func selector, - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSender : class -#endif - { - ArgumentExceptionHelper.ThrowIfNull(sender); - ArgumentExceptionHelper.ThrowIfNull(obs1); - ArgumentExceptionHelper.ThrowIfNull(obs2); - ArgumentExceptionHelper.ThrowIfNull(obs3); - ArgumentExceptionHelper.ThrowIfNull(selector); - - var o1 = ObservableChainHelpers.SwitchLatest(sender, obs1); - var o2 = ObservableChainHelpers.SwitchLatest(sender, obs2); - var o3 = ObservableChainHelpers.SwitchLatest(sender, obs3); - return CombineLatestObservable.Create( - o1, - o2, - o3, - (v1, v2, v3) => selector(v1, v2, v3)); - } - -#if NET8_0_OR_GREATER - /// - /// Observes 4 observable properties with different types on the specified sender and applies a selector to the combined latest values. - /// - /// The type of the sender to monitor for property changes. - /// The return type of the selector. - /// The element type of observable property 1. - /// The element type of observable property 2. - /// The element type of observable property 3. - /// The element type of observable property 4. - /// The sender instance to observe for property changes. - /// An expression that selects observable property 1 to observe. - /// An expression that selects observable property 2 to observe. - /// An expression that selects observable property 3 to observe. - /// An expression that selects observable property 4 to observe. - /// A function that combines the latest values from all observables. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// An observable sequence of selector results. - [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] - public static IObservable WhenAnyObservable( - this TSender sender, - Expression?>> obs1, - Expression?>> obs2, - Expression?>> obs3, - Expression?>> obs4, - Func selector, - [CallerArgumentExpression("obs1")] string obs1Expression = "", - [CallerArgumentExpression("obs2")] string obs2Expression = "", - [CallerArgumentExpression("obs3")] string obs3Expression = "", - [CallerArgumentExpression("obs4")] string obs4Expression = "", - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSender : class -#else - /// - /// Observes 4 observable properties with different types on the specified sender and applies a selector to the combined latest values. - /// - /// The type of the sender to monitor for property changes. - /// The return type of the selector. - /// The element type of observable property 1. - /// The element type of observable property 2. - /// The element type of observable property 3. - /// The element type of observable property 4. - /// The sender instance to observe for property changes. - /// An expression that selects observable property 1 to observe. - /// An expression that selects observable property 2 to observe. - /// An expression that selects observable property 3 to observe. - /// An expression that selects observable property 4 to observe. - /// A function that combines the latest values from all observables. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// An observable sequence of selector results. - [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] - public static IObservable WhenAnyObservable( - this TSender sender, - Expression?>> obs1, - Expression?>> obs2, - Expression?>> obs3, - Expression?>> obs4, - Func selector, - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSender : class -#endif - { - ArgumentExceptionHelper.ThrowIfNull(sender); - ArgumentExceptionHelper.ThrowIfNull(obs1); - ArgumentExceptionHelper.ThrowIfNull(obs2); - ArgumentExceptionHelper.ThrowIfNull(obs3); - ArgumentExceptionHelper.ThrowIfNull(obs4); - ArgumentExceptionHelper.ThrowIfNull(selector); - - var o1 = ObservableChainHelpers.SwitchLatest(sender, obs1); - var o2 = ObservableChainHelpers.SwitchLatest(sender, obs2); - var o3 = ObservableChainHelpers.SwitchLatest(sender, obs3); - var o4 = ObservableChainHelpers.SwitchLatest(sender, obs4); - return CombineLatestObservable.Create( - o1, - o2, - o3, - o4, - (v1, v2, v3, v4) => selector(v1, v2, v3, v4)); - } - -#if NET8_0_OR_GREATER - /// - /// Observes 5 observable properties with different types on the specified sender and applies a selector to the combined latest values. - /// - /// The type of the sender to monitor for property changes. - /// The return type of the selector. - /// The element type of observable property 1. - /// The element type of observable property 2. - /// The element type of observable property 3. - /// The element type of observable property 4. - /// The element type of observable property 5. - /// The sender instance to observe for property changes. - /// An expression that selects observable property 1 to observe. - /// An expression that selects observable property 2 to observe. - /// An expression that selects observable property 3 to observe. - /// An expression that selects observable property 4 to observe. - /// An expression that selects observable property 5 to observe. - /// A function that combines the latest values from all observables. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// An observable sequence of selector results. - [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] - public static IObservable WhenAnyObservable( - this TSender sender, - Expression?>> obs1, - Expression?>> obs2, - Expression?>> obs3, - Expression?>> obs4, - Expression?>> obs5, - Func selector, - [CallerArgumentExpression("obs1")] string obs1Expression = "", - [CallerArgumentExpression("obs2")] string obs2Expression = "", - [CallerArgumentExpression("obs3")] string obs3Expression = "", - [CallerArgumentExpression("obs4")] string obs4Expression = "", - [CallerArgumentExpression("obs5")] string obs5Expression = "", - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSender : class -#else - /// - /// Observes 5 observable properties with different types on the specified sender and applies a selector to the combined latest values. - /// - /// The type of the sender to monitor for property changes. - /// The return type of the selector. - /// The element type of observable property 1. - /// The element type of observable property 2. - /// The element type of observable property 3. - /// The element type of observable property 4. - /// The element type of observable property 5. - /// The sender instance to observe for property changes. - /// An expression that selects observable property 1 to observe. - /// An expression that selects observable property 2 to observe. - /// An expression that selects observable property 3 to observe. - /// An expression that selects observable property 4 to observe. - /// An expression that selects observable property 5 to observe. - /// A function that combines the latest values from all observables. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// An observable sequence of selector results. - [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] - public static IObservable WhenAnyObservable( - this TSender sender, - Expression?>> obs1, - Expression?>> obs2, - Expression?>> obs3, - Expression?>> obs4, - Expression?>> obs5, - Func selector, - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSender : class -#endif - { - ArgumentExceptionHelper.ThrowIfNull(sender); - ArgumentExceptionHelper.ThrowIfNull(obs1); - ArgumentExceptionHelper.ThrowIfNull(obs2); - ArgumentExceptionHelper.ThrowIfNull(obs3); - ArgumentExceptionHelper.ThrowIfNull(obs4); - ArgumentExceptionHelper.ThrowIfNull(obs5); - ArgumentExceptionHelper.ThrowIfNull(selector); - - var o1 = ObservableChainHelpers.SwitchLatest(sender, obs1); - var o2 = ObservableChainHelpers.SwitchLatest(sender, obs2); - var o3 = ObservableChainHelpers.SwitchLatest(sender, obs3); - var o4 = ObservableChainHelpers.SwitchLatest(sender, obs4); - var o5 = ObservableChainHelpers.SwitchLatest(sender, obs5); - return CombineLatestObservable.Create( - o1, - o2, - o3, - o4, - o5, - (v1, v2, v3, v4, v5) => selector(v1, v2, v3, v4, v5)); - } - -#if NET8_0_OR_GREATER - /// - /// Observes 6 observable properties with different types on the specified sender and applies a selector to the combined latest values. - /// - /// The type of the sender to monitor for property changes. - /// The return type of the selector. - /// The element type of observable property 1. - /// The element type of observable property 2. - /// The element type of observable property 3. - /// The element type of observable property 4. - /// The element type of observable property 5. - /// The element type of observable property 6. - /// The sender instance to observe for property changes. - /// An expression that selects observable property 1 to observe. - /// An expression that selects observable property 2 to observe. - /// An expression that selects observable property 3 to observe. - /// An expression that selects observable property 4 to observe. - /// An expression that selects observable property 5 to observe. - /// An expression that selects observable property 6 to observe. - /// A function that combines the latest values from all observables. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// An observable sequence of selector results. - [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] - public static IObservable WhenAnyObservable( - this TSender sender, - Expression?>> obs1, - Expression?>> obs2, - Expression?>> obs3, - Expression?>> obs4, - Expression?>> obs5, - Expression?>> obs6, - Func selector, - [CallerArgumentExpression("obs1")] string obs1Expression = "", - [CallerArgumentExpression("obs2")] string obs2Expression = "", - [CallerArgumentExpression("obs3")] string obs3Expression = "", - [CallerArgumentExpression("obs4")] string obs4Expression = "", - [CallerArgumentExpression("obs5")] string obs5Expression = "", - [CallerArgumentExpression("obs6")] string obs6Expression = "", - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSender : class -#else - /// - /// Observes 6 observable properties with different types on the specified sender and applies a selector to the combined latest values. - /// - /// The type of the sender to monitor for property changes. - /// The return type of the selector. - /// The element type of observable property 1. - /// The element type of observable property 2. - /// The element type of observable property 3. - /// The element type of observable property 4. - /// The element type of observable property 5. - /// The element type of observable property 6. - /// The sender instance to observe for property changes. - /// An expression that selects observable property 1 to observe. - /// An expression that selects observable property 2 to observe. - /// An expression that selects observable property 3 to observe. - /// An expression that selects observable property 4 to observe. - /// An expression that selects observable property 5 to observe. - /// An expression that selects observable property 6 to observe. - /// A function that combines the latest values from all observables. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// An observable sequence of selector results. - [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] - public static IObservable WhenAnyObservable( - this TSender sender, - Expression?>> obs1, - Expression?>> obs2, - Expression?>> obs3, - Expression?>> obs4, - Expression?>> obs5, - Expression?>> obs6, - Func selector, - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSender : class -#endif - { - ArgumentExceptionHelper.ThrowIfNull(sender); - ArgumentExceptionHelper.ThrowIfNull(obs1); - ArgumentExceptionHelper.ThrowIfNull(obs2); - ArgumentExceptionHelper.ThrowIfNull(obs3); - ArgumentExceptionHelper.ThrowIfNull(obs4); - ArgumentExceptionHelper.ThrowIfNull(obs5); - ArgumentExceptionHelper.ThrowIfNull(obs6); - ArgumentExceptionHelper.ThrowIfNull(selector); - - var o1 = ObservableChainHelpers.SwitchLatest(sender, obs1); - var o2 = ObservableChainHelpers.SwitchLatest(sender, obs2); - var o3 = ObservableChainHelpers.SwitchLatest(sender, obs3); - var o4 = ObservableChainHelpers.SwitchLatest(sender, obs4); - var o5 = ObservableChainHelpers.SwitchLatest(sender, obs5); - var o6 = ObservableChainHelpers.SwitchLatest(sender, obs6); - return CombineLatestObservable.Create( - o1, - o2, - o3, - o4, - o5, - o6, - (v1, v2, v3, v4, v5, v6) => selector(v1, v2, v3, v4, v5, v6)); - } - -#if NET8_0_OR_GREATER - /// - /// Observes 7 observable properties with different types on the specified sender and applies a selector to the combined latest values. - /// - /// The type of the sender to monitor for property changes. - /// The return type of the selector. - /// The element type of observable property 1. - /// The element type of observable property 2. - /// The element type of observable property 3. - /// The element type of observable property 4. - /// The element type of observable property 5. - /// The element type of observable property 6. - /// The element type of observable property 7. - /// The sender instance to observe for property changes. - /// An expression that selects observable property 1 to observe. - /// An expression that selects observable property 2 to observe. - /// An expression that selects observable property 3 to observe. - /// An expression that selects observable property 4 to observe. - /// An expression that selects observable property 5 to observe. - /// An expression that selects observable property 6 to observe. - /// An expression that selects observable property 7 to observe. - /// A function that combines the latest values from all observables. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// An observable sequence of selector results. - [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] - public static IObservable WhenAnyObservable( - this TSender sender, - Expression?>> obs1, - Expression?>> obs2, - Expression?>> obs3, - Expression?>> obs4, - Expression?>> obs5, - Expression?>> obs6, - Expression?>> obs7, - Func selector, - [CallerArgumentExpression("obs1")] string obs1Expression = "", - [CallerArgumentExpression("obs2")] string obs2Expression = "", - [CallerArgumentExpression("obs3")] string obs3Expression = "", - [CallerArgumentExpression("obs4")] string obs4Expression = "", - [CallerArgumentExpression("obs5")] string obs5Expression = "", - [CallerArgumentExpression("obs6")] string obs6Expression = "", - [CallerArgumentExpression("obs7")] string obs7Expression = "", - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSender : class -#else - /// - /// Observes 7 observable properties with different types on the specified sender and applies a selector to the combined latest values. - /// - /// The type of the sender to monitor for property changes. - /// The return type of the selector. - /// The element type of observable property 1. - /// The element type of observable property 2. - /// The element type of observable property 3. - /// The element type of observable property 4. - /// The element type of observable property 5. - /// The element type of observable property 6. - /// The element type of observable property 7. - /// The sender instance to observe for property changes. - /// An expression that selects observable property 1 to observe. - /// An expression that selects observable property 2 to observe. - /// An expression that selects observable property 3 to observe. - /// An expression that selects observable property 4 to observe. - /// An expression that selects observable property 5 to observe. - /// An expression that selects observable property 6 to observe. - /// An expression that selects observable property 7 to observe. - /// A function that combines the latest values from all observables. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// An observable sequence of selector results. - [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] - public static IObservable WhenAnyObservable( - this TSender sender, - Expression?>> obs1, - Expression?>> obs2, - Expression?>> obs3, - Expression?>> obs4, - Expression?>> obs5, - Expression?>> obs6, - Expression?>> obs7, - Func selector, - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSender : class -#endif - { - ArgumentExceptionHelper.ThrowIfNull(sender); - ArgumentExceptionHelper.ThrowIfNull(obs1); - ArgumentExceptionHelper.ThrowIfNull(obs2); - ArgumentExceptionHelper.ThrowIfNull(obs3); - ArgumentExceptionHelper.ThrowIfNull(obs4); - ArgumentExceptionHelper.ThrowIfNull(obs5); - ArgumentExceptionHelper.ThrowIfNull(obs6); - ArgumentExceptionHelper.ThrowIfNull(obs7); - ArgumentExceptionHelper.ThrowIfNull(selector); - - var o1 = ObservableChainHelpers.SwitchLatest(sender, obs1); - var o2 = ObservableChainHelpers.SwitchLatest(sender, obs2); - var o3 = ObservableChainHelpers.SwitchLatest(sender, obs3); - var o4 = ObservableChainHelpers.SwitchLatest(sender, obs4); - var o5 = ObservableChainHelpers.SwitchLatest(sender, obs5); - var o6 = ObservableChainHelpers.SwitchLatest(sender, obs6); - var o7 = ObservableChainHelpers.SwitchLatest(sender, obs7); - return CombineLatestObservable.Create( - o1, - o2, - o3, - o4, - o5, - o6, - o7, - (v1, v2, v3, v4, v5, v6, v7) => selector(v1, v2, v3, v4, v5, v6, v7)); - } - -#if NET8_0_OR_GREATER - /// - /// Observes 8 observable properties with different types on the specified sender and applies a selector to the combined latest values. - /// - /// The type of the sender to monitor for property changes. - /// The return type of the selector. - /// The element type of observable property 1. - /// The element type of observable property 2. - /// The element type of observable property 3. - /// The element type of observable property 4. - /// The element type of observable property 5. - /// The element type of observable property 6. - /// The element type of observable property 7. - /// The element type of observable property 8. - /// The sender instance to observe for property changes. - /// An expression that selects observable property 1 to observe. - /// An expression that selects observable property 2 to observe. - /// An expression that selects observable property 3 to observe. - /// An expression that selects observable property 4 to observe. - /// An expression that selects observable property 5 to observe. - /// An expression that selects observable property 6 to observe. - /// An expression that selects observable property 7 to observe. - /// An expression that selects observable property 8 to observe. - /// A function that combines the latest values from all observables. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// An observable sequence of selector results. - [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] - public static IObservable WhenAnyObservable( - this TSender sender, - Expression?>> obs1, - Expression?>> obs2, - Expression?>> obs3, - Expression?>> obs4, - Expression?>> obs5, - Expression?>> obs6, - Expression?>> obs7, - Expression?>> obs8, - Func selector, - [CallerArgumentExpression("obs1")] string obs1Expression = "", - [CallerArgumentExpression("obs2")] string obs2Expression = "", - [CallerArgumentExpression("obs3")] string obs3Expression = "", - [CallerArgumentExpression("obs4")] string obs4Expression = "", - [CallerArgumentExpression("obs5")] string obs5Expression = "", - [CallerArgumentExpression("obs6")] string obs6Expression = "", - [CallerArgumentExpression("obs7")] string obs7Expression = "", - [CallerArgumentExpression("obs8")] string obs8Expression = "", - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSender : class -#else - /// - /// Observes 8 observable properties with different types on the specified sender and applies a selector to the combined latest values. - /// - /// The type of the sender to monitor for property changes. - /// The return type of the selector. - /// The element type of observable property 1. - /// The element type of observable property 2. - /// The element type of observable property 3. - /// The element type of observable property 4. - /// The element type of observable property 5. - /// The element type of observable property 6. - /// The element type of observable property 7. - /// The element type of observable property 8. - /// The sender instance to observe for property changes. - /// An expression that selects observable property 1 to observe. - /// An expression that selects observable property 2 to observe. - /// An expression that selects observable property 3 to observe. - /// An expression that selects observable property 4 to observe. - /// An expression that selects observable property 5 to observe. - /// An expression that selects observable property 6 to observe. - /// An expression that selects observable property 7 to observe. - /// An expression that selects observable property 8 to observe. - /// A function that combines the latest values from all observables. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// An observable sequence of selector results. - [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] - public static IObservable WhenAnyObservable( - this TSender sender, - Expression?>> obs1, - Expression?>> obs2, - Expression?>> obs3, - Expression?>> obs4, - Expression?>> obs5, - Expression?>> obs6, - Expression?>> obs7, - Expression?>> obs8, - Func selector, - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSender : class -#endif - { - ArgumentExceptionHelper.ThrowIfNull(sender); - ArgumentExceptionHelper.ThrowIfNull(obs1); - ArgumentExceptionHelper.ThrowIfNull(obs2); - ArgumentExceptionHelper.ThrowIfNull(obs3); - ArgumentExceptionHelper.ThrowIfNull(obs4); - ArgumentExceptionHelper.ThrowIfNull(obs5); - ArgumentExceptionHelper.ThrowIfNull(obs6); - ArgumentExceptionHelper.ThrowIfNull(obs7); - ArgumentExceptionHelper.ThrowIfNull(obs8); - ArgumentExceptionHelper.ThrowIfNull(selector); - - var o1 = ObservableChainHelpers.SwitchLatest(sender, obs1); - var o2 = ObservableChainHelpers.SwitchLatest(sender, obs2); - var o3 = ObservableChainHelpers.SwitchLatest(sender, obs3); - var o4 = ObservableChainHelpers.SwitchLatest(sender, obs4); - var o5 = ObservableChainHelpers.SwitchLatest(sender, obs5); - var o6 = ObservableChainHelpers.SwitchLatest(sender, obs6); - var o7 = ObservableChainHelpers.SwitchLatest(sender, obs7); - var o8 = ObservableChainHelpers.SwitchLatest(sender, obs8); - return CombineLatestObservable.Create( - o1, - o2, - o3, - o4, - o5, - o6, - o7, - o8, - (v1, v2, v3, v4, v5, v6, v7, v8) => selector(v1, v2, v3, v4, v5, v6, v7, v8)); - } - -#if NET8_0_OR_GREATER - /// - /// Observes 9 observable properties with different types on the specified sender and applies a selector to the combined latest values. - /// - /// The type of the sender to monitor for property changes. - /// The return type of the selector. - /// The element type of observable property 1. - /// The element type of observable property 2. - /// The element type of observable property 3. - /// The element type of observable property 4. - /// The element type of observable property 5. - /// The element type of observable property 6. - /// The element type of observable property 7. - /// The element type of observable property 8. - /// The element type of observable property 9. - /// The sender instance to observe for property changes. - /// An expression that selects observable property 1 to observe. - /// An expression that selects observable property 2 to observe. - /// An expression that selects observable property 3 to observe. - /// An expression that selects observable property 4 to observe. - /// An expression that selects observable property 5 to observe. - /// An expression that selects observable property 6 to observe. - /// An expression that selects observable property 7 to observe. - /// An expression that selects observable property 8 to observe. - /// An expression that selects observable property 9 to observe. - /// A function that combines the latest values from all observables. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// An observable sequence of selector results. - [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] - public static IObservable WhenAnyObservable( - this TSender sender, - Expression?>> obs1, - Expression?>> obs2, - Expression?>> obs3, - Expression?>> obs4, - Expression?>> obs5, - Expression?>> obs6, - Expression?>> obs7, - Expression?>> obs8, - Expression?>> obs9, - Func selector, - [CallerArgumentExpression("obs1")] string obs1Expression = "", - [CallerArgumentExpression("obs2")] string obs2Expression = "", - [CallerArgumentExpression("obs3")] string obs3Expression = "", - [CallerArgumentExpression("obs4")] string obs4Expression = "", - [CallerArgumentExpression("obs5")] string obs5Expression = "", - [CallerArgumentExpression("obs6")] string obs6Expression = "", - [CallerArgumentExpression("obs7")] string obs7Expression = "", - [CallerArgumentExpression("obs8")] string obs8Expression = "", - [CallerArgumentExpression("obs9")] string obs9Expression = "", - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSender : class -#else - /// - /// Observes 9 observable properties with different types on the specified sender and applies a selector to the combined latest values. - /// - /// The type of the sender to monitor for property changes. - /// The return type of the selector. - /// The element type of observable property 1. - /// The element type of observable property 2. - /// The element type of observable property 3. - /// The element type of observable property 4. - /// The element type of observable property 5. - /// The element type of observable property 6. - /// The element type of observable property 7. - /// The element type of observable property 8. - /// The element type of observable property 9. - /// The sender instance to observe for property changes. - /// An expression that selects observable property 1 to observe. - /// An expression that selects observable property 2 to observe. - /// An expression that selects observable property 3 to observe. - /// An expression that selects observable property 4 to observe. - /// An expression that selects observable property 5 to observe. - /// An expression that selects observable property 6 to observe. - /// An expression that selects observable property 7 to observe. - /// An expression that selects observable property 8 to observe. - /// An expression that selects observable property 9 to observe. - /// A function that combines the latest values from all observables. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// An observable sequence of selector results. - [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] - public static IObservable WhenAnyObservable( - this TSender sender, - Expression?>> obs1, - Expression?>> obs2, - Expression?>> obs3, - Expression?>> obs4, - Expression?>> obs5, - Expression?>> obs6, - Expression?>> obs7, - Expression?>> obs8, - Expression?>> obs9, - Func selector, - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSender : class -#endif - { - ArgumentExceptionHelper.ThrowIfNull(sender); - ArgumentExceptionHelper.ThrowIfNull(obs1); - ArgumentExceptionHelper.ThrowIfNull(obs2); - ArgumentExceptionHelper.ThrowIfNull(obs3); - ArgumentExceptionHelper.ThrowIfNull(obs4); - ArgumentExceptionHelper.ThrowIfNull(obs5); - ArgumentExceptionHelper.ThrowIfNull(obs6); - ArgumentExceptionHelper.ThrowIfNull(obs7); - ArgumentExceptionHelper.ThrowIfNull(obs8); - ArgumentExceptionHelper.ThrowIfNull(obs9); - ArgumentExceptionHelper.ThrowIfNull(selector); - - var o1 = ObservableChainHelpers.SwitchLatest(sender, obs1); - var o2 = ObservableChainHelpers.SwitchLatest(sender, obs2); - var o3 = ObservableChainHelpers.SwitchLatest(sender, obs3); - var o4 = ObservableChainHelpers.SwitchLatest(sender, obs4); - var o5 = ObservableChainHelpers.SwitchLatest(sender, obs5); - var o6 = ObservableChainHelpers.SwitchLatest(sender, obs6); - var o7 = ObservableChainHelpers.SwitchLatest(sender, obs7); - var o8 = ObservableChainHelpers.SwitchLatest(sender, obs8); - var o9 = ObservableChainHelpers.SwitchLatest(sender, obs9); - return CombineLatestObservable.Create( - o1, - o2, - o3, - o4, - o5, - o6, - o7, - o8, - o9, - (v1, v2, v3, v4, v5, v6, v7, v8, v9) => selector(v1, v2, v3, v4, v5, v6, v7, v8, v9)); - } - -#if NET8_0_OR_GREATER - /// - /// Observes 10 observable properties with different types on the specified sender and applies a selector to the combined latest values. - /// - /// The type of the sender to monitor for property changes. - /// The return type of the selector. - /// The element type of observable property 1. - /// The element type of observable property 2. - /// The element type of observable property 3. - /// The element type of observable property 4. - /// The element type of observable property 5. - /// The element type of observable property 6. - /// The element type of observable property 7. - /// The element type of observable property 8. - /// The element type of observable property 9. - /// The element type of observable property 10. - /// The sender instance to observe for property changes. - /// An expression that selects observable property 1 to observe. - /// An expression that selects observable property 2 to observe. - /// An expression that selects observable property 3 to observe. - /// An expression that selects observable property 4 to observe. - /// An expression that selects observable property 5 to observe. - /// An expression that selects observable property 6 to observe. - /// An expression that selects observable property 7 to observe. - /// An expression that selects observable property 8 to observe. - /// An expression that selects observable property 9 to observe. - /// An expression that selects observable property 10 to observe. - /// A function that combines the latest values from all observables. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// An observable sequence of selector results. - [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] - public static IObservable WhenAnyObservable( - this TSender sender, - Expression?>> obs1, - Expression?>> obs2, - Expression?>> obs3, - Expression?>> obs4, - Expression?>> obs5, - Expression?>> obs6, - Expression?>> obs7, - Expression?>> obs8, - Expression?>> obs9, - Expression?>> obs10, - Func selector, - [CallerArgumentExpression("obs1")] string obs1Expression = "", - [CallerArgumentExpression("obs2")] string obs2Expression = "", - [CallerArgumentExpression("obs3")] string obs3Expression = "", - [CallerArgumentExpression("obs4")] string obs4Expression = "", - [CallerArgumentExpression("obs5")] string obs5Expression = "", - [CallerArgumentExpression("obs6")] string obs6Expression = "", - [CallerArgumentExpression("obs7")] string obs7Expression = "", - [CallerArgumentExpression("obs8")] string obs8Expression = "", - [CallerArgumentExpression("obs9")] string obs9Expression = "", - [CallerArgumentExpression("obs10")] string obs10Expression = "", - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSender : class -#else - /// - /// Observes 10 observable properties with different types on the specified sender and applies a selector to the combined latest values. - /// - /// The type of the sender to monitor for property changes. - /// The return type of the selector. - /// The element type of observable property 1. - /// The element type of observable property 2. - /// The element type of observable property 3. - /// The element type of observable property 4. - /// The element type of observable property 5. - /// The element type of observable property 6. - /// The element type of observable property 7. - /// The element type of observable property 8. - /// The element type of observable property 9. - /// The element type of observable property 10. - /// The sender instance to observe for property changes. - /// An expression that selects observable property 1 to observe. - /// An expression that selects observable property 2 to observe. - /// An expression that selects observable property 3 to observe. - /// An expression that selects observable property 4 to observe. - /// An expression that selects observable property 5 to observe. - /// An expression that selects observable property 6 to observe. - /// An expression that selects observable property 7 to observe. - /// An expression that selects observable property 8 to observe. - /// An expression that selects observable property 9 to observe. - /// An expression that selects observable property 10 to observe. - /// A function that combines the latest values from all observables. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// An observable sequence of selector results. - [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] - public static IObservable WhenAnyObservable( - this TSender sender, - Expression?>> obs1, - Expression?>> obs2, - Expression?>> obs3, - Expression?>> obs4, - Expression?>> obs5, - Expression?>> obs6, - Expression?>> obs7, - Expression?>> obs8, - Expression?>> obs9, - Expression?>> obs10, - Func selector, - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSender : class -#endif - { - ArgumentExceptionHelper.ThrowIfNull(sender); - ArgumentExceptionHelper.ThrowIfNull(obs1); - ArgumentExceptionHelper.ThrowIfNull(obs2); - ArgumentExceptionHelper.ThrowIfNull(obs3); - ArgumentExceptionHelper.ThrowIfNull(obs4); - ArgumentExceptionHelper.ThrowIfNull(obs5); - ArgumentExceptionHelper.ThrowIfNull(obs6); - ArgumentExceptionHelper.ThrowIfNull(obs7); - ArgumentExceptionHelper.ThrowIfNull(obs8); - ArgumentExceptionHelper.ThrowIfNull(obs9); - ArgumentExceptionHelper.ThrowIfNull(obs10); - ArgumentExceptionHelper.ThrowIfNull(selector); - - var o1 = ObservableChainHelpers.SwitchLatest(sender, obs1); - var o2 = ObservableChainHelpers.SwitchLatest(sender, obs2); - var o3 = ObservableChainHelpers.SwitchLatest(sender, obs3); - var o4 = ObservableChainHelpers.SwitchLatest(sender, obs4); - var o5 = ObservableChainHelpers.SwitchLatest(sender, obs5); - var o6 = ObservableChainHelpers.SwitchLatest(sender, obs6); - var o7 = ObservableChainHelpers.SwitchLatest(sender, obs7); - var o8 = ObservableChainHelpers.SwitchLatest(sender, obs8); - var o9 = ObservableChainHelpers.SwitchLatest(sender, obs9); - var o10 = ObservableChainHelpers.SwitchLatest(sender, obs10); - return CombineLatestObservable.Create( - o1, - o2, - o3, - o4, - o5, - o6, - o7, - o8, - o9, - o10, - selector); - } - -#if NET8_0_OR_GREATER - /// - /// Observes 11 observable properties with different types on the specified sender and applies a selector to the combined latest values. - /// - /// The type of the sender to monitor for property changes. - /// The return type of the selector. - /// The element type of observable property 1. - /// The element type of observable property 2. - /// The element type of observable property 3. - /// The element type of observable property 4. - /// The element type of observable property 5. - /// The element type of observable property 6. - /// The element type of observable property 7. - /// The element type of observable property 8. - /// The element type of observable property 9. - /// The element type of observable property 10. - /// The element type of observable property 11. - /// The sender instance to observe for property changes. - /// An expression that selects observable property 1 to observe. - /// An expression that selects observable property 2 to observe. - /// An expression that selects observable property 3 to observe. - /// An expression that selects observable property 4 to observe. - /// An expression that selects observable property 5 to observe. - /// An expression that selects observable property 6 to observe. - /// An expression that selects observable property 7 to observe. - /// An expression that selects observable property 8 to observe. - /// An expression that selects observable property 9 to observe. - /// An expression that selects observable property 10 to observe. - /// An expression that selects observable property 11 to observe. - /// A function that combines the latest values from all observables. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// An observable sequence of selector results. - [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] - public static IObservable WhenAnyObservable( - this TSender sender, - Expression?>> obs1, - Expression?>> obs2, - Expression?>> obs3, - Expression?>> obs4, - Expression?>> obs5, - Expression?>> obs6, - Expression?>> obs7, - Expression?>> obs8, - Expression?>> obs9, - Expression?>> obs10, - Expression?>> obs11, - Func selector, - [CallerArgumentExpression("obs1")] string obs1Expression = "", - [CallerArgumentExpression("obs2")] string obs2Expression = "", - [CallerArgumentExpression("obs3")] string obs3Expression = "", - [CallerArgumentExpression("obs4")] string obs4Expression = "", - [CallerArgumentExpression("obs5")] string obs5Expression = "", - [CallerArgumentExpression("obs6")] string obs6Expression = "", - [CallerArgumentExpression("obs7")] string obs7Expression = "", - [CallerArgumentExpression("obs8")] string obs8Expression = "", - [CallerArgumentExpression("obs9")] string obs9Expression = "", - [CallerArgumentExpression("obs10")] string obs10Expression = "", - [CallerArgumentExpression("obs11")] string obs11Expression = "", - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSender : class -#else - /// - /// Observes 11 observable properties with different types on the specified sender and applies a selector to the combined latest values. - /// - /// The type of the sender to monitor for property changes. - /// The return type of the selector. - /// The element type of observable property 1. - /// The element type of observable property 2. - /// The element type of observable property 3. - /// The element type of observable property 4. - /// The element type of observable property 5. - /// The element type of observable property 6. - /// The element type of observable property 7. - /// The element type of observable property 8. - /// The element type of observable property 9. - /// The element type of observable property 10. - /// The element type of observable property 11. - /// The sender instance to observe for property changes. - /// An expression that selects observable property 1 to observe. - /// An expression that selects observable property 2 to observe. - /// An expression that selects observable property 3 to observe. - /// An expression that selects observable property 4 to observe. - /// An expression that selects observable property 5 to observe. - /// An expression that selects observable property 6 to observe. - /// An expression that selects observable property 7 to observe. - /// An expression that selects observable property 8 to observe. - /// An expression that selects observable property 9 to observe. - /// An expression that selects observable property 10 to observe. - /// An expression that selects observable property 11 to observe. - /// A function that combines the latest values from all observables. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// An observable sequence of selector results. - [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] - public static IObservable WhenAnyObservable( - this TSender sender, - Expression?>> obs1, - Expression?>> obs2, - Expression?>> obs3, - Expression?>> obs4, - Expression?>> obs5, - Expression?>> obs6, - Expression?>> obs7, - Expression?>> obs8, - Expression?>> obs9, - Expression?>> obs10, - Expression?>> obs11, - Func selector, - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSender : class -#endif - { - ArgumentExceptionHelper.ThrowIfNull(sender); - ArgumentExceptionHelper.ThrowIfNull(obs1); - ArgumentExceptionHelper.ThrowIfNull(obs2); - ArgumentExceptionHelper.ThrowIfNull(obs3); - ArgumentExceptionHelper.ThrowIfNull(obs4); - ArgumentExceptionHelper.ThrowIfNull(obs5); - ArgumentExceptionHelper.ThrowIfNull(obs6); - ArgumentExceptionHelper.ThrowIfNull(obs7); - ArgumentExceptionHelper.ThrowIfNull(obs8); - ArgumentExceptionHelper.ThrowIfNull(obs9); - ArgumentExceptionHelper.ThrowIfNull(obs10); - ArgumentExceptionHelper.ThrowIfNull(obs11); - ArgumentExceptionHelper.ThrowIfNull(selector); - - var o1 = ObservableChainHelpers.SwitchLatest(sender, obs1); - var o2 = ObservableChainHelpers.SwitchLatest(sender, obs2); - var o3 = ObservableChainHelpers.SwitchLatest(sender, obs3); - var o4 = ObservableChainHelpers.SwitchLatest(sender, obs4); - var o5 = ObservableChainHelpers.SwitchLatest(sender, obs5); - var o6 = ObservableChainHelpers.SwitchLatest(sender, obs6); - var o7 = ObservableChainHelpers.SwitchLatest(sender, obs7); - var o8 = ObservableChainHelpers.SwitchLatest(sender, obs8); - var o9 = ObservableChainHelpers.SwitchLatest(sender, obs9); - var o10 = ObservableChainHelpers.SwitchLatest(sender, obs10); - var o11 = ObservableChainHelpers.SwitchLatest(sender, obs11); - return CombineLatestObservable.Create( - o1, - o2, - o3, - o4, - o5, - o6, - o7, - o8, - o9, - o10, - o11, - selector); - } - -#if NET8_0_OR_GREATER - /// - /// Observes 12 observable properties with different types on the specified sender and applies a selector to the combined latest values. - /// - /// The type of the sender to monitor for property changes. - /// The return type of the selector. - /// The element type of observable property 1. - /// The element type of observable property 2. - /// The element type of observable property 3. - /// The element type of observable property 4. - /// The element type of observable property 5. - /// The element type of observable property 6. - /// The element type of observable property 7. - /// The element type of observable property 8. - /// The element type of observable property 9. - /// The element type of observable property 10. - /// The element type of observable property 11. - /// The element type of observable property 12. - /// The sender instance to observe for property changes. - /// An expression that selects observable property 1 to observe. - /// An expression that selects observable property 2 to observe. - /// An expression that selects observable property 3 to observe. - /// An expression that selects observable property 4 to observe. - /// An expression that selects observable property 5 to observe. - /// An expression that selects observable property 6 to observe. - /// An expression that selects observable property 7 to observe. - /// An expression that selects observable property 8 to observe. - /// An expression that selects observable property 9 to observe. - /// An expression that selects observable property 10 to observe. - /// An expression that selects observable property 11 to observe. - /// An expression that selects observable property 12 to observe. - /// A function that combines the latest values from all observables. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The caller argument expression for . Auto-populated by the compiler. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// An observable sequence of selector results. - [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] - public static IObservable WhenAnyObservable( - this TSender sender, - Expression?>> obs1, - Expression?>> obs2, - Expression?>> obs3, - Expression?>> obs4, - Expression?>> obs5, - Expression?>> obs6, - Expression?>> obs7, - Expression?>> obs8, - Expression?>> obs9, - Expression?>> obs10, - Expression?>> obs11, - Expression?>> obs12, - Func selector, - [CallerArgumentExpression("obs1")] string obs1Expression = "", - [CallerArgumentExpression("obs2")] string obs2Expression = "", - [CallerArgumentExpression("obs3")] string obs3Expression = "", - [CallerArgumentExpression("obs4")] string obs4Expression = "", - [CallerArgumentExpression("obs5")] string obs5Expression = "", - [CallerArgumentExpression("obs6")] string obs6Expression = "", - [CallerArgumentExpression("obs7")] string obs7Expression = "", - [CallerArgumentExpression("obs8")] string obs8Expression = "", - [CallerArgumentExpression("obs9")] string obs9Expression = "", - [CallerArgumentExpression("obs10")] string obs10Expression = "", - [CallerArgumentExpression("obs11")] string obs11Expression = "", - [CallerArgumentExpression("obs12")] string obs12Expression = "", - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSender : class -#else - /// - /// Observes 12 observable properties with different types on the specified sender and applies a selector to the combined latest values. - /// - /// The type of the sender to monitor for property changes. - /// The return type of the selector. - /// The element type of observable property 1. - /// The element type of observable property 2. - /// The element type of observable property 3. - /// The element type of observable property 4. - /// The element type of observable property 5. - /// The element type of observable property 6. - /// The element type of observable property 7. - /// The element type of observable property 8. - /// The element type of observable property 9. - /// The element type of observable property 10. - /// The element type of observable property 11. - /// The element type of observable property 12. - /// The sender instance to observe for property changes. - /// An expression that selects observable property 1 to observe. - /// An expression that selects observable property 2 to observe. - /// An expression that selects observable property 3 to observe. - /// An expression that selects observable property 4 to observe. - /// An expression that selects observable property 5 to observe. - /// An expression that selects observable property 6 to observe. - /// An expression that selects observable property 7 to observe. - /// An expression that selects observable property 8 to observe. - /// An expression that selects observable property 9 to observe. - /// An expression that selects observable property 10 to observe. - /// An expression that selects observable property 11 to observe. - /// An expression that selects observable property 12 to observe. - /// A function that combines the latest values from all observables. - /// The source file path of the caller. Auto-populated by the compiler. - /// The source line number of the caller. Auto-populated by the compiler. - /// An observable sequence of selector results. - [RequiresUnreferencedCode("Runtime observation fallback uses reflection-based expression analysis.")] - public static IObservable WhenAnyObservable( - this TSender sender, - Expression?>> obs1, - Expression?>> obs2, - Expression?>> obs3, - Expression?>> obs4, - Expression?>> obs5, - Expression?>> obs6, - Expression?>> obs7, - Expression?>> obs8, - Expression?>> obs9, - Expression?>> obs10, - Expression?>> obs11, - Expression?>> obs12, - Func selector, - [CallerFilePath] string callerFilePath = "", - [CallerLineNumber] int callerLineNumber = 0) - where TSender : class -#endif - { - ArgumentExceptionHelper.ThrowIfNull(sender); - ArgumentExceptionHelper.ThrowIfNull(obs1); - ArgumentExceptionHelper.ThrowIfNull(obs2); - ArgumentExceptionHelper.ThrowIfNull(obs3); - ArgumentExceptionHelper.ThrowIfNull(obs4); - ArgumentExceptionHelper.ThrowIfNull(obs5); - ArgumentExceptionHelper.ThrowIfNull(obs6); - ArgumentExceptionHelper.ThrowIfNull(obs7); - ArgumentExceptionHelper.ThrowIfNull(obs8); - ArgumentExceptionHelper.ThrowIfNull(obs9); - ArgumentExceptionHelper.ThrowIfNull(obs10); - ArgumentExceptionHelper.ThrowIfNull(obs11); - ArgumentExceptionHelper.ThrowIfNull(obs12); - ArgumentExceptionHelper.ThrowIfNull(selector); - - var o1 = ObservableChainHelpers.SwitchLatest(sender, obs1); - var o2 = ObservableChainHelpers.SwitchLatest(sender, obs2); - var o3 = ObservableChainHelpers.SwitchLatest(sender, obs3); - var o4 = ObservableChainHelpers.SwitchLatest(sender, obs4); - var o5 = ObservableChainHelpers.SwitchLatest(sender, obs5); - var o6 = ObservableChainHelpers.SwitchLatest(sender, obs6); - var o7 = ObservableChainHelpers.SwitchLatest(sender, obs7); - var o8 = ObservableChainHelpers.SwitchLatest(sender, obs8); - var o9 = ObservableChainHelpers.SwitchLatest(sender, obs9); - var o10 = ObservableChainHelpers.SwitchLatest(sender, obs10); - var o11 = ObservableChainHelpers.SwitchLatest(sender, obs11); - var o12 = ObservableChainHelpers.SwitchLatest(sender, obs12); - return CombineLatestObservable.Create( - o1, - o2, - o3, - o4, - o5, - o6, - o7, - o8, - o9, - o10, - o11, - o12, - selector); - } } diff --git a/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenAnyValue.Selectors.cs b/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenAnyValue.Selectors.cs index 34a3601..2b669bd 100644 --- a/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenAnyValue.Selectors.cs +++ b/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenAnyValue.Selectors.cs @@ -2,6 +2,7 @@ // ReactiveUI Association Incorporated licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System.Diagnostics.CodeAnalysis; using ReactiveUI.Binding.Observables; namespace ReactiveUI.Binding; @@ -75,6 +76,7 @@ public static IObservable WhenAnyValue( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the selector result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable WhenAnyValue( this TSender sender, Expression> property1, @@ -134,6 +136,7 @@ public static IObservable WhenAnyValue( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the selector result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable WhenAnyValue( this TSender sender, Expression> property1, @@ -206,6 +209,7 @@ public static IObservable WhenAnyValue( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the selector result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable WhenAnyValue( this TSender sender, Expression> property1, @@ -243,6 +247,7 @@ public static IObservable WhenAnyValue( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the selector result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable WhenAnyValue( this TSender sender, Expression> property1, @@ -288,6 +293,8 @@ public static IObservable WhenAnyValue( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the selector result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenAnyValue( this TSender sender, Expression> property1, @@ -330,6 +337,7 @@ public static IObservable WhenAnyValue( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the selector result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable WhenAnyValue( this TSender sender, Expression> property1, @@ -380,6 +388,8 @@ public static IObservable WhenAnyValue( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the selector result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenAnyValue( this TSender sender, Expression> property1, @@ -427,6 +437,7 @@ public static IObservable WhenAnyValueThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the selector result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable WhenAnyValue( this TSender sender, Expression> property1, @@ -482,6 +493,8 @@ public static IObservable WhenAnyValueThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the selector result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenAnyValue( this TSender sender, Expression> property1, @@ -534,6 +547,7 @@ public static IObservable WhenAnyValueThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the selector result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenAnyValue( this TSender sender, Expression> property1, @@ -601,6 +615,8 @@ public static IObservable WhenAnyValueThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the selector result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenAnyValue( this TSender sender, Expression> property1, @@ -658,6 +674,7 @@ public static IObservable WhenAnyValueThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the selector result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenAnyValue( this TSender sender, Expression> property1, @@ -731,6 +748,8 @@ public static IObservable WhenAnyValueThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the selector result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenAnyValue( this TSender sender, Expression> property1, @@ -793,6 +812,7 @@ public static IObservable WhenAnyValueThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the selector result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenAnyValue( this TSender sender, Expression> property1, @@ -872,6 +892,8 @@ public static IObservable WhenAnyValueThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the selector result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenAnyValue( this TSender sender, Expression> property1, @@ -939,6 +961,7 @@ public static IObservable WhenAnyValueThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the selector result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenAnyValue( this TSender sender, Expression> property1, @@ -1024,6 +1047,8 @@ public static IObservable WhenAnyValueThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the selector result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenAnyValue( this TSender sender, Expression> property1, @@ -1096,6 +1121,7 @@ public static IObservable WhenAnyValueThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the selector result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenAnyValue( this TSender sender, Expression> property1, @@ -1187,6 +1213,8 @@ public static IObservable WhenAnyValueThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the selector result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenAnyValue( this TSender sender, Expression> property1, @@ -1264,6 +1292,7 @@ public static IObservable WhenAnyValueThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the selector result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenAnyValue( this TSender sender, Expression> property1, @@ -1361,6 +1390,8 @@ public static IObservable WhenAnyValueThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the selector result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenAnyValue( this TSender sender, Expression> property1, @@ -1443,6 +1474,7 @@ public static IObservable WhenAnyValueThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the selector result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenAnyValue( this TSender sender, Expression> property1, @@ -1546,6 +1578,8 @@ public static IObservable WhenAnyValueThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the selector result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenAnyValue< TSender, T1, @@ -1649,6 +1683,7 @@ public static IObservable WhenAnyValue< /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the selector result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenAnyValue( this TSender sender, Expression> property1, @@ -1758,6 +1793,8 @@ public static IObservable WhenAnyValueThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the selector result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenAnyValue< TSender, T1, @@ -1867,6 +1904,7 @@ public static IObservable WhenAnyValue< /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the selector result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenAnyValue( this TSender sender, Expression> property1, @@ -1982,6 +2020,8 @@ public static IObservable WhenAnyValueThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the selector result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenAnyValue< TSender, T1, @@ -2097,6 +2137,7 @@ public static IObservable WhenAnyValue< /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the selector result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenAnyValue( this TSender sender, Expression> property1, diff --git a/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenAnyValue.cs b/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenAnyValue.cs index c5fa104..768e0b3 100644 --- a/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenAnyValue.cs +++ b/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenAnyValue.cs @@ -2,14 +2,13 @@ // ReactiveUI Association Incorporated licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System.Diagnostics.CodeAnalysis; using ReactiveUI.Binding.Fallback; using ReactiveUI.Binding.Observables; namespace ReactiveUI.Binding; -/// -/// Extension methods for observing property changes using ReactiveUI conventions (WhenAnyValue). -/// +/// Extension methods for observing property changes using ReactiveUI conventions (WhenAnyValue). public static partial class ReactiveUIBindingExtensions { #if NET8_0_OR_GREATER @@ -112,7 +111,7 @@ public static IObservable WhenAnyValue( return CombineLatestObservable.Create( RuntimeObservationFallback.WhenAnyValue(sender, property1), RuntimeObservationFallback.WhenAnyValue(sender, property2), - (v1, v2) => (v1, v2)); + static (v1, v2) => (v1, v2)); } #if NET8_0_OR_GREATER @@ -133,6 +132,7 @@ public static IObservable WhenAnyValue( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3)> WhenAnyValue( this TSender sender, Expression> property1, @@ -181,7 +181,7 @@ public static IObservable WhenAnyValue( RuntimeObservationFallback.WhenAnyValue(sender, property1), RuntimeObservationFallback.WhenAnyValue(sender, property2), RuntimeObservationFallback.WhenAnyValue(sender, property3), - (v1, v2, v3) => (v1, v2, v3)); + static (v1, v2, v3) => (v1, v2, v3)); } #if NET8_0_OR_GREATER @@ -205,6 +205,8 @@ public static IObservable WhenAnyValue( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4)> WhenAnyValue< TSender, T1, @@ -266,7 +268,7 @@ public static IObservable WhenAnyValue( RuntimeObservationFallback.WhenAnyValue(sender, property2), RuntimeObservationFallback.WhenAnyValue(sender, property3), RuntimeObservationFallback.WhenAnyValue(sender, property4), - (v1, v2, v3, v4) => (v1, v2, v3, v4)); + static (v1, v2, v3, v4) => (v1, v2, v3, v4)); } #if NET8_0_OR_GREATER @@ -293,6 +295,8 @@ public static IObservable WhenAnyValue( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5)> WhenAnyValue< TSender, T1, @@ -338,6 +342,7 @@ public static IObservable WhenAnyValue( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5)> WhenAnyValue( this TSender sender, Expression> property1, @@ -363,7 +368,7 @@ public static IObservable WhenAnyValue( RuntimeObservationFallback.WhenAnyValue(sender, property3), RuntimeObservationFallback.WhenAnyValue(sender, property4), RuntimeObservationFallback.WhenAnyValue(sender, property5), - (v1, v2, v3, v4, v5) => (v1, v2, v3, v4, v5)); + static (v1, v2, v3, v4, v5) => (v1, v2, v3, v4, v5)); } #if NET8_0_OR_GREATER @@ -393,6 +398,8 @@ public static IObservable WhenAnyValue( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6)> WhenAnyValue( this TSender sender, @@ -438,6 +445,7 @@ public static IObservable WhenAnyValue( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6)> WhenAnyValue( this TSender sender, Expression> property1, @@ -466,7 +474,7 @@ public static IObservable WhenAnyValue( RuntimeObservationFallback.WhenAnyValue(sender, property4), RuntimeObservationFallback.WhenAnyValue(sender, property5), RuntimeObservationFallback.WhenAnyValue(sender, property6), - (v1, v2, v3, v4, v5, v6) => (v1, v2, v3, v4, v5, v6)); + static (v1, v2, v3, v4, v5, v6) => (v1, v2, v3, v4, v5, v6)); } #if NET8_0_OR_GREATER @@ -499,6 +507,8 @@ public static IObservable WhenAnyValue( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7)> WhenAnyValue( @@ -550,6 +560,7 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7)> WhenAnyValue( this TSender sender, Expression> property1, @@ -581,7 +592,7 @@ public static RuntimeObservationFallback.WhenAnyValue(sender, property5), RuntimeObservationFallback.WhenAnyValue(sender, property6), RuntimeObservationFallback.WhenAnyValue(sender, property7), - (v1, v2, v3, v4, v5, v6, v7) => (v1, v2, v3, v4, v5, v6, v7)); + static (v1, v2, v3, v4, v5, v6, v7) => (v1, v2, v3, v4, v5, v6, v7)); } #if NET8_0_OR_GREATER @@ -617,6 +628,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 @@ -674,6 +687,7 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 property8)> WhenAnyValue( this TSender sender, Expression> property1, @@ -708,7 +722,7 @@ public static RuntimeObservationFallback.WhenAnyValue(sender, property6), RuntimeObservationFallback.WhenAnyValue(sender, property7), RuntimeObservationFallback.WhenAnyValue(sender, property8), - (v1, v2, v3, v4, v5, v6, v7, v8) => (v1, v2, v3, v4, v5, v6, v7, v8)); + static (v1, v2, v3, v4, v5, v6, v7, v8) => (v1, v2, v3, v4, v5, v6, v7, v8)); } #if NET8_0_OR_GREATER @@ -747,6 +761,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 @@ -809,6 +825,7 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable<( T1 property1, T2 property2, @@ -855,7 +872,7 @@ public static RuntimeObservationFallback.WhenAnyValue(sender, property7), RuntimeObservationFallback.WhenAnyValue(sender, property8), RuntimeObservationFallback.WhenAnyValue(sender, property9), - (v1, v2, v3, v4, v5, v6, v7, v8, v9) => (v1, v2, v3, v4, v5, v6, v7, v8, v9)); + static (v1, v2, v3, v4, v5, v6, v7, v8, v9) => (v1, v2, v3, v4, v5, v6, v7, v8, v9)); } #if NET8_0_OR_GREATER @@ -897,6 +914,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 @@ -964,6 +983,7 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable<( T1 property1, T2 property2, @@ -1014,7 +1034,7 @@ public static RuntimeObservationFallback.WhenAnyValue(sender, property8), RuntimeObservationFallback.WhenAnyValue(sender, property9), RuntimeObservationFallback.WhenAnyValue(sender, property10), - (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10)); + static (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10)); } #if NET8_0_OR_GREATER @@ -1059,6 +1079,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 @@ -1143,6 +1165,7 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable<( T1 property1, T2 property2, @@ -1197,7 +1220,7 @@ public static RuntimeObservationFallback.WhenAnyValue(sender, property9), RuntimeObservationFallback.WhenAnyValue(sender, property10), RuntimeObservationFallback.WhenAnyValue(sender, property11), - (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11)); + static (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11)); } #if NET8_0_OR_GREATER @@ -1245,6 +1268,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 @@ -1335,6 +1360,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable<( T1 property1, T2 property2, @@ -1393,7 +1420,7 @@ public static RuntimeObservationFallback.WhenAnyValue(sender, property10), RuntimeObservationFallback.WhenAnyValue(sender, property11), RuntimeObservationFallback.WhenAnyValue(sender, property12), - (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12)); + static (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12)); } #if NET8_0_OR_GREATER @@ -1444,6 +1471,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 @@ -1540,6 +1569,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable<( T1 property1, T2 property2, @@ -1602,7 +1633,7 @@ public static RuntimeObservationFallback.WhenAnyValue(sender, property11), RuntimeObservationFallback.WhenAnyValue(sender, property12), RuntimeObservationFallback.WhenAnyValue(sender, property13), - (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) => + static (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13)); } @@ -1657,6 +1688,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 @@ -1745,6 +1778,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable<( T1 property1, T2 property2, @@ -1811,7 +1846,7 @@ public static RuntimeObservationFallback.WhenAnyValue(sender, property12), RuntimeObservationFallback.WhenAnyValue(sender, property13), RuntimeObservationFallback.WhenAnyValue(sender, property14), - (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) => + static (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14)); } @@ -1869,6 +1904,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 @@ -1962,6 +1999,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable<( T1 property1, T2 property2, @@ -2032,7 +2071,7 @@ public static RuntimeObservationFallback.WhenAnyValue(sender, property13), RuntimeObservationFallback.WhenAnyValue(sender, property14), RuntimeObservationFallback.WhenAnyValue(sender, property15), - (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) => + static (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15)); } @@ -2093,6 +2132,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 @@ -2208,6 +2249,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable<( T1 property1, T2 property2, @@ -2282,7 +2325,7 @@ public static RuntimeObservationFallback.WhenAnyValue(sender, property14), RuntimeObservationFallback.WhenAnyValue(sender, property15), RuntimeObservationFallback.WhenAnyValue(sender, property16), - (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) => (v1, v2, v3, v4, v5, v6, v7, v8, + static (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16)); } } diff --git a/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenChanged.Selectors.cs b/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenChanged.Selectors.cs index 8ba6f9e..5beef7e 100644 --- a/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenChanged.Selectors.cs +++ b/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenChanged.Selectors.cs @@ -2,13 +2,12 @@ // ReactiveUI Association Incorporated licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System.Diagnostics.CodeAnalysis; using ReactiveUI.Binding.Observables; namespace ReactiveUI.Binding; -/// -/// Extension methods for observing property changes with a conversion function (WhenChanged with selector). -/// +/// Extension methods for observing property changes with a conversion function (WhenChanged with selector). public static partial class ReactiveUIBindingExtensions { #if NET8_0_OR_GREATER @@ -28,6 +27,7 @@ public static partial class ReactiveUIBindingExtensions /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable WhenChanged( this TObj objectToMonitor, Expression> property1, @@ -90,6 +90,7 @@ public static IObservable WhenChanged( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable WhenChanged( this TObj objectToMonitor, Expression> property1, @@ -162,6 +163,7 @@ public static IObservable WhenChanged( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable WhenChanged( this TObj objectToMonitor, Expression> property1, @@ -199,6 +201,7 @@ public static IObservable WhenChanged( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable WhenChanged( this TObj objectToMonitor, Expression> property1, @@ -244,6 +247,8 @@ public static IObservable WhenChanged( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenChanged( this TObj objectToMonitor, Expression> property1, @@ -286,6 +291,7 @@ public static IObservable WhenChangedThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable WhenChanged( this TObj objectToMonitor, Expression> property1, @@ -336,6 +342,8 @@ public static IObservable WhenChangedThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenChanged( this TObj objectToMonitor, Expression> property1, @@ -383,6 +391,7 @@ public static IObservable WhenChangedThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable WhenChanged( this TObj objectToMonitor, Expression> property1, @@ -438,6 +447,8 @@ public static IObservable WhenChangedThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenChanged( this TObj objectToMonitor, Expression> property1, @@ -490,6 +501,7 @@ public static IObservable WhenChangedThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenChanged( this TObj objectToMonitor, Expression> property1, @@ -557,6 +569,8 @@ public static IObservable WhenChangedThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenChanged( this TObj objectToMonitor, Expression> property1, @@ -614,6 +628,7 @@ public static IObservable WhenChangedThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenChanged( this TObj objectToMonitor, Expression> property1, @@ -687,6 +702,8 @@ public static IObservable WhenChangedThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenChanged( this TObj objectToMonitor, Expression> property1, @@ -749,6 +766,7 @@ public static IObservable WhenChangedThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenChanged( this TObj objectToMonitor, Expression> property1, @@ -828,6 +846,8 @@ public static IObservable WhenChangedThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenChanged( this TObj objectToMonitor, Expression> property1, @@ -895,6 +915,7 @@ public static IObservable WhenChangedThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenChanged( this TObj objectToMonitor, Expression> property1, @@ -980,6 +1001,8 @@ public static IObservable WhenChangedThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenChanged( this TObj objectToMonitor, Expression> property1, @@ -1052,6 +1075,7 @@ public static IObservable WhenChangedThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenChanged( this TObj objectToMonitor, Expression> property1, @@ -1143,6 +1167,8 @@ public static IObservable WhenChangedThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenChanged( this TObj objectToMonitor, Expression> property1, @@ -1220,6 +1246,7 @@ public static IObservable WhenChangedThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenChanged( this TObj objectToMonitor, Expression> property1, @@ -1317,6 +1344,8 @@ public static IObservable WhenChangedThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenChanged< TObj, T1, @@ -1414,6 +1443,7 @@ public static IObservable WhenChanged< /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenChanged( this TObj objectToMonitor, Expression> property1, @@ -1517,6 +1547,8 @@ public static IObservable WhenChangedThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenChanged< TObj, T1, @@ -1620,6 +1652,7 @@ public static IObservable WhenChanged< /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenChanged( this TObj objectToMonitor, Expression> property1, @@ -1729,6 +1762,8 @@ public static IObservable WhenChangedThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenChanged< TObj, T1, @@ -1838,6 +1873,7 @@ public static IObservable WhenChanged< /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenChanged( this TObj objectToMonitor, Expression> property1, @@ -1953,6 +1989,8 @@ public static IObservable WhenChangedThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenChanged< TObj, T1, @@ -2068,6 +2106,7 @@ public static IObservable WhenChanged< /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result when any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenChanged( this TObj objectToMonitor, Expression> property1, diff --git a/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenChanged.cs b/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenChanged.cs index ff4cafe..81266f0 100644 --- a/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenChanged.cs +++ b/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenChanged.cs @@ -2,20 +2,17 @@ // ReactiveUI Association Incorporated licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System.Diagnostics.CodeAnalysis; using ReactiveUI.Binding.Fallback; using ReactiveUI.Binding.Observables; namespace ReactiveUI.Binding; -/// -/// Extension methods for observing property changes after they occur (WhenChanged). -/// +/// Extension methods for observing property changes after they occur (WhenChanged). public static partial class ReactiveUIBindingExtensions { #if NET8_0_OR_GREATER - /// - /// Observes a property change on the specified object and emits the value after it changes. - /// + /// Observes a property change on the specified object and emits the value after it changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The object instance to observe for property changes. @@ -33,9 +30,7 @@ public static IObservable WhenChanged( [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes a property change on the specified object and emits the value after it changes. - /// + /// Observes a property change on the specified object and emits the value after it changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The object instance to observe for property changes. @@ -58,9 +53,7 @@ public static IObservable WhenChanged( } #if NET8_0_OR_GREATER - /// - /// Observes changes on 2 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 2 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -84,9 +77,7 @@ public static IObservable WhenChanged( [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes changes on 2 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 2 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -113,9 +104,7 @@ public static IObservable WhenChanged( } #if NET8_0_OR_GREATER - /// - /// Observes changes on 3 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 3 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -130,6 +119,7 @@ public static IObservable WhenChanged( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3)> WhenChanged( this TObj objectToMonitor, Expression> property1, @@ -145,9 +135,7 @@ public static IObservable WhenChanged( [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes changes on 3 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 3 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -178,9 +166,7 @@ public static IObservable WhenChanged( } #if NET8_0_OR_GREATER - /// - /// Observes changes on 4 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 4 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -198,6 +184,8 @@ public static IObservable WhenChanged( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4)> WhenChanged< TObj, T1, @@ -221,9 +209,7 @@ public static IObservable WhenChanged( [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes changes on 4 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 4 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -259,13 +245,11 @@ public static IObservable WhenChanged( RuntimeObservationFallback.WhenChanged(objectToMonitor, property2), RuntimeObservationFallback.WhenChanged(objectToMonitor, property3), RuntimeObservationFallback.WhenChanged(objectToMonitor, property4), - (v1, v2, v3, v4) => (v1, v2, v3, v4)); + static (v1, v2, v3, v4) => (v1, v2, v3, v4)); } #if NET8_0_OR_GREATER - /// - /// Observes changes on 5 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 5 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -286,6 +270,8 @@ public static IObservable WhenChanged( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5)> WhenChanged< TObj, T1, @@ -313,9 +299,7 @@ public static IObservable WhenChanged( [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes changes on 5 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 5 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -331,6 +315,7 @@ public static IObservable WhenChanged( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5)> WhenChanged( this TObj objectToMonitor, Expression> property1, @@ -356,13 +341,11 @@ public static IObservable WhenChanged( RuntimeObservationFallback.WhenChanged(objectToMonitor, property3), RuntimeObservationFallback.WhenChanged(objectToMonitor, property4), RuntimeObservationFallback.WhenChanged(objectToMonitor, property5), - (v1, v2, v3, v4, v5) => (v1, v2, v3, v4, v5)); + static (v1, v2, v3, v4, v5) => (v1, v2, v3, v4, v5)); } #if NET8_0_OR_GREATER - /// - /// Observes changes on 6 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 6 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -386,6 +369,8 @@ public static IObservable WhenChanged( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6)> WhenChanged( this TObj objectToMonitor, @@ -411,9 +396,7 @@ public static IObservable WhenChanged( [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes changes on 6 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 6 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -431,6 +414,7 @@ public static IObservable WhenChanged( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6)> WhenChanged( this TObj objectToMonitor, Expression> property1, @@ -459,13 +443,11 @@ public static IObservable WhenChanged( RuntimeObservationFallback.WhenChanged(objectToMonitor, property4), RuntimeObservationFallback.WhenChanged(objectToMonitor, property5), RuntimeObservationFallback.WhenChanged(objectToMonitor, property6), - (v1, v2, v3, v4, v5, v6) => (v1, v2, v3, v4, v5, v6)); + static (v1, v2, v3, v4, v5, v6) => (v1, v2, v3, v4, v5, v6)); } #if NET8_0_OR_GREATER - /// - /// Observes changes on 7 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 7 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -492,6 +474,8 @@ public static IObservable WhenChanged( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7)> WhenChanged( @@ -521,9 +505,7 @@ public static [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes changes on 7 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 7 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -543,6 +525,7 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7)> WhenChanged( this TObj objectToMonitor, Expression> property1, @@ -574,13 +557,11 @@ public static RuntimeObservationFallback.WhenChanged(objectToMonitor, property5), RuntimeObservationFallback.WhenChanged(objectToMonitor, property6), RuntimeObservationFallback.WhenChanged(objectToMonitor, property7), - (v1, v2, v3, v4, v5, v6, v7) => (v1, v2, v3, v4, v5, v6, v7)); + static (v1, v2, v3, v4, v5, v6, v7) => (v1, v2, v3, v4, v5, v6, v7)); } #if NET8_0_OR_GREATER - /// - /// Observes changes on 8 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 8 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -610,6 +591,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 @@ -643,9 +626,7 @@ public static [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes changes on 8 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 8 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -667,6 +648,7 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 property8)> WhenChanged( this TObj objectToMonitor, Expression> property1, @@ -701,13 +683,11 @@ public static RuntimeObservationFallback.WhenChanged(objectToMonitor, property6), RuntimeObservationFallback.WhenChanged(objectToMonitor, property7), RuntimeObservationFallback.WhenChanged(objectToMonitor, property8), - (v1, v2, v3, v4, v5, v6, v7, v8) => (v1, v2, v3, v4, v5, v6, v7, v8)); + static (v1, v2, v3, v4, v5, v6, v7, v8) => (v1, v2, v3, v4, v5, v6, v7, v8)); } #if NET8_0_OR_GREATER - /// - /// Observes changes on 9 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 9 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -740,6 +720,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 @@ -776,9 +758,7 @@ public static [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes changes on 9 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 9 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -802,6 +782,7 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable<( T1 property1, T2 property2, @@ -848,13 +829,11 @@ public static RuntimeObservationFallback.WhenChanged(objectToMonitor, property7), RuntimeObservationFallback.WhenChanged(objectToMonitor, property8), RuntimeObservationFallback.WhenChanged(objectToMonitor, property9), - (v1, v2, v3, v4, v5, v6, v7, v8, v9) => (v1, v2, v3, v4, v5, v6, v7, v8, v9)); + static (v1, v2, v3, v4, v5, v6, v7, v8, v9) => (v1, v2, v3, v4, v5, v6, v7, v8, v9)); } #if NET8_0_OR_GREATER - /// - /// Observes changes on 10 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 10 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -890,6 +869,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 @@ -929,9 +910,7 @@ public static [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes changes on 10 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 10 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -957,6 +936,7 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable<( T1 property1, T2 property2, @@ -1007,13 +987,11 @@ public static RuntimeObservationFallback.WhenChanged(objectToMonitor, property8), RuntimeObservationFallback.WhenChanged(objectToMonitor, property9), RuntimeObservationFallback.WhenChanged(objectToMonitor, property10), - (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10)); + static (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10)); } #if NET8_0_OR_GREATER - /// - /// Observes changes on 11 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 11 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -1052,6 +1030,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 @@ -1106,9 +1086,7 @@ public static [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes changes on 11 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 11 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -1136,6 +1114,7 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable<( T1 property1, T2 property2, @@ -1190,13 +1169,11 @@ public static RuntimeObservationFallback.WhenChanged(objectToMonitor, property9), RuntimeObservationFallback.WhenChanged(objectToMonitor, property10), RuntimeObservationFallback.WhenChanged(objectToMonitor, property11), - (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11)); + static (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11)); } #if NET8_0_OR_GREATER - /// - /// Observes changes on 12 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 12 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -1238,6 +1215,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 @@ -1296,9 +1275,7 @@ public static [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes changes on 12 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 12 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -1328,6 +1305,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable<( T1 property1, T2 property2, @@ -1386,13 +1365,11 @@ public static RuntimeObservationFallback.WhenChanged(objectToMonitor, property10), RuntimeObservationFallback.WhenChanged(objectToMonitor, property11), RuntimeObservationFallback.WhenChanged(objectToMonitor, property12), - (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12)); + static (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12)); } #if NET8_0_OR_GREATER - /// - /// Observes changes on 13 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 13 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -1437,6 +1414,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 @@ -1499,9 +1478,7 @@ public static [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes changes on 13 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 13 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -1533,6 +1510,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable<( T1 property1, T2 property2, @@ -1595,14 +1574,12 @@ public static RuntimeObservationFallback.WhenChanged(objectToMonitor, property11), RuntimeObservationFallback.WhenChanged(objectToMonitor, property12), RuntimeObservationFallback.WhenChanged(objectToMonitor, property13), - (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) => + static (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13)); } #if NET8_0_OR_GREATER - /// - /// Observes changes on 14 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 14 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -1650,6 +1627,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 @@ -1702,9 +1681,7 @@ public static [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes changes on 14 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 14 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -1738,6 +1715,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable<( T1 property1, T2 property2, @@ -1804,14 +1783,12 @@ public static RuntimeObservationFallback.WhenChanged(objectToMonitor, property12), RuntimeObservationFallback.WhenChanged(objectToMonitor, property13), RuntimeObservationFallback.WhenChanged(objectToMonitor, property14), - (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) => + static (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14)); } #if NET8_0_OR_GREATER - /// - /// Observes changes on 15 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 15 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -1862,6 +1839,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 @@ -1917,9 +1896,7 @@ public static [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes changes on 15 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 15 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -1955,6 +1932,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable<( T1 property1, T2 property2, @@ -2025,14 +2004,12 @@ public static RuntimeObservationFallback.WhenChanged(objectToMonitor, property13), RuntimeObservationFallback.WhenChanged(objectToMonitor, property14), RuntimeObservationFallback.WhenChanged(objectToMonitor, property15), - (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) => + static (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15)); } #if NET8_0_OR_GREATER - /// - /// Observes changes on 16 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 16 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -2086,6 +2063,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 @@ -2161,9 +2140,7 @@ public static [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes changes on 16 properties on the specified object and emits their values as a tuple after any property changes. - /// + /// Observes changes on 16 properties on the specified object and emits their values as a tuple after any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -2201,6 +2178,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values when any of them changes. + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable<( T1 property1, T2 property2, @@ -2275,7 +2254,7 @@ public static RuntimeObservationFallback.WhenChanged(objectToMonitor, property14), RuntimeObservationFallback.WhenChanged(objectToMonitor, property15), RuntimeObservationFallback.WhenChanged(objectToMonitor, property16), - (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) => (v1, v2, v3, v4, v5, v6, v7, v8, + static (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16)); } } diff --git a/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenChanging.Selectors.cs b/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenChanging.Selectors.cs index de90f17..b370b95 100644 --- a/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenChanging.Selectors.cs +++ b/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenChanging.Selectors.cs @@ -2,6 +2,7 @@ // ReactiveUI Association Incorporated licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System.Diagnostics.CodeAnalysis; using ReactiveUI.Binding.Observables; namespace ReactiveUI.Binding; @@ -28,6 +29,7 @@ public static partial class ReactiveUIBindingExtensions /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result before any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable WhenChanging( this TObj objectToMonitor, Expression> property1, @@ -90,6 +92,7 @@ public static IObservable WhenChanging( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result before any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable WhenChanging( this TObj objectToMonitor, Expression> property1, @@ -162,6 +165,7 @@ public static IObservable WhenChanging( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result before any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable WhenChanging( this TObj objectToMonitor, Expression> property1, @@ -199,6 +203,7 @@ public static IObservable WhenChanging( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result before any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable WhenChanging( this TObj objectToMonitor, Expression> property1, @@ -244,6 +249,8 @@ public static IObservable WhenChanging( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result before any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenChanging( this TObj objectToMonitor, Expression> property1, @@ -286,6 +293,7 @@ public static IObservable WhenChangingThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result before any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable WhenChanging( this TObj objectToMonitor, Expression> property1, @@ -336,6 +344,8 @@ public static IObservable WhenChangingThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result before any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenChanging( this TObj objectToMonitor, Expression> property1, @@ -383,6 +393,7 @@ public static IObservable WhenChangingThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result before any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable WhenChanging( this TObj objectToMonitor, Expression> property1, @@ -438,6 +449,8 @@ public static IObservable WhenChangingThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result before any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenChanging( this TObj objectToMonitor, Expression> property1, @@ -490,6 +503,7 @@ public static IObservable WhenChangingThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result before any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenChanging( this TObj objectToMonitor, Expression> property1, @@ -557,6 +571,8 @@ public static IObservable WhenChangingThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result before any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenChanging( this TObj objectToMonitor, Expression> property1, @@ -614,6 +630,7 @@ public static IObservable WhenChangingThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result before any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenChanging( this TObj objectToMonitor, Expression> property1, @@ -687,6 +704,8 @@ public static IObservable WhenChangingThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result before any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenChanging( this TObj objectToMonitor, Expression> property1, @@ -749,6 +768,7 @@ public static IObservable WhenChangingThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result before any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenChanging( this TObj objectToMonitor, Expression> property1, @@ -828,6 +848,8 @@ public static IObservable WhenChangingThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result before any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenChanging( this TObj objectToMonitor, Expression> property1, @@ -895,6 +917,7 @@ public static IObservable WhenChangingThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result before any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenChanging( this TObj objectToMonitor, Expression> property1, @@ -980,6 +1003,8 @@ public static IObservable WhenChangingThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result before any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenChanging( this TObj objectToMonitor, Expression> property1, @@ -1052,6 +1077,7 @@ public static IObservable WhenChangingThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result before any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenChanging( this TObj objectToMonitor, Expression> property1, @@ -1143,6 +1169,8 @@ public static IObservable WhenChangingThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result before any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenChanging( this TObj objectToMonitor, Expression> property1, @@ -1220,6 +1248,7 @@ public static IObservable WhenChangingThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result before any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenChanging( this TObj objectToMonitor, Expression> property1, @@ -1317,6 +1346,8 @@ public static IObservable WhenChangingThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result before any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenChanging< TObj, T1, @@ -1414,6 +1445,7 @@ public static IObservable WhenChanging< /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result before any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenChanging( this TObj objectToMonitor, Expression> property1, @@ -1517,6 +1549,8 @@ public static IObservable WhenChangingThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result before any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenChanging< TObj, T1, @@ -1620,6 +1654,7 @@ public static IObservable WhenChanging< /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result before any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenChanging( this TObj objectToMonitor, Expression> property1, @@ -1729,6 +1764,8 @@ public static IObservable WhenChangingThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result before any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenChanging< TObj, T1, @@ -1838,6 +1875,7 @@ public static IObservable WhenChanging< /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result before any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenChanging( this TObj objectToMonitor, Expression> property1, @@ -1953,6 +1991,8 @@ public static IObservable WhenChangingThe source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result before any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable WhenChanging< TObj, T1, @@ -2068,6 +2108,7 @@ public static IObservable WhenChanging< /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits the converted result before any of the observed properties changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable WhenChanging( this TObj objectToMonitor, Expression> property1, diff --git a/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenChanging.cs b/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenChanging.cs index 1cd5dcb..048e23e 100644 --- a/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenChanging.cs +++ b/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.WhenChanging.cs @@ -2,20 +2,17 @@ // ReactiveUI Association Incorporated licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System.Diagnostics.CodeAnalysis; using ReactiveUI.Binding.Fallback; using ReactiveUI.Binding.Observables; namespace ReactiveUI.Binding; -/// -/// Extension methods for observing property changes before they occur (WhenChanging). -/// +/// Extension methods for observing property changes before they occur (WhenChanging). public static partial class ReactiveUIBindingExtensions { #if NET8_0_OR_GREATER - /// - /// Observes a property on the specified object and emits the value before it changes. - /// + /// Observes a property on the specified object and emits the value before it changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The object instance to observe for property changes. @@ -33,9 +30,7 @@ public static IObservable WhenChanging( [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes a property on the specified object and emits the value before it changes. - /// + /// Observes a property on the specified object and emits the value before it changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The object instance to observe for property changes. @@ -58,9 +53,7 @@ public static IObservable WhenChanging( } #if NET8_0_OR_GREATER - /// - /// Observes 2 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 2 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -84,9 +77,7 @@ public static IObservable WhenChanging( [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes 2 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 2 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -112,13 +103,11 @@ public static IObservable WhenChanging( return CombineLatestObservable.Create( RuntimeObservationFallback.WhenChanging(objectToMonitor, property1), RuntimeObservationFallback.WhenChanging(objectToMonitor, property2), - (v1, v2) => (v1, v2)); + static (v1, v2) => (v1, v2)); } #if NET8_0_OR_GREATER - /// - /// Observes 3 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 3 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -133,6 +122,7 @@ public static IObservable WhenChanging( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values before any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3)> WhenChanging( this TObj objectToMonitor, Expression> property1, @@ -148,9 +138,7 @@ public static IObservable WhenChanging( [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes 3 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 3 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -181,13 +169,11 @@ public static IObservable WhenChanging( RuntimeObservationFallback.WhenChanging(objectToMonitor, property1), RuntimeObservationFallback.WhenChanging(objectToMonitor, property2), RuntimeObservationFallback.WhenChanging(objectToMonitor, property3), - (v1, v2, v3) => (v1, v2, v3)); + static (v1, v2, v3) => (v1, v2, v3)); } #if NET8_0_OR_GREATER - /// - /// Observes 4 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 4 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -205,6 +191,8 @@ public static IObservable WhenChanging( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values before any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4)> WhenChanging< TObj, T1, @@ -228,9 +216,7 @@ public static IObservable WhenChanging( [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes 4 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 4 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -266,13 +252,11 @@ public static IObservable WhenChanging( RuntimeObservationFallback.WhenChanging(objectToMonitor, property2), RuntimeObservationFallback.WhenChanging(objectToMonitor, property3), RuntimeObservationFallback.WhenChanging(objectToMonitor, property4), - (v1, v2, v3, v4) => (v1, v2, v3, v4)); + static (v1, v2, v3, v4) => (v1, v2, v3, v4)); } #if NET8_0_OR_GREATER - /// - /// Observes 5 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 5 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -293,6 +277,8 @@ public static IObservable WhenChanging( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values before any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5)> WhenChanging< TObj, T1, @@ -320,9 +306,7 @@ public static IObservable WhenChanging( [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes 5 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 5 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -338,6 +322,7 @@ public static IObservable WhenChanging( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values before any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5)> WhenChanging( this TObj objectToMonitor, Expression> property1, @@ -363,13 +348,11 @@ public static IObservable WhenChanging( RuntimeObservationFallback.WhenChanging(objectToMonitor, property3), RuntimeObservationFallback.WhenChanging(objectToMonitor, property4), RuntimeObservationFallback.WhenChanging(objectToMonitor, property5), - (v1, v2, v3, v4, v5) => (v1, v2, v3, v4, v5)); + static (v1, v2, v3, v4, v5) => (v1, v2, v3, v4, v5)); } #if NET8_0_OR_GREATER - /// - /// Observes 6 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 6 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -393,6 +376,8 @@ public static IObservable WhenChanging( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values before any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6)> WhenChanging( this TObj objectToMonitor, @@ -418,9 +403,7 @@ public static IObservable WhenChanging( [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes 6 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 6 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -438,6 +421,7 @@ public static IObservable WhenChanging( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values before any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6)> WhenChanging( this TObj objectToMonitor, Expression> property1, @@ -466,13 +450,11 @@ public static IObservable WhenChanging( RuntimeObservationFallback.WhenChanging(objectToMonitor, property4), RuntimeObservationFallback.WhenChanging(objectToMonitor, property5), RuntimeObservationFallback.WhenChanging(objectToMonitor, property6), - (v1, v2, v3, v4, v5, v6) => (v1, v2, v3, v4, v5, v6)); + static (v1, v2, v3, v4, v5, v6) => (v1, v2, v3, v4, v5, v6)); } #if NET8_0_OR_GREATER - /// - /// Observes 7 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 7 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -499,6 +481,8 @@ public static IObservable WhenChanging( /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values before any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7)> WhenChanging( @@ -528,9 +512,7 @@ public static [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes 7 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 7 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -550,6 +532,7 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values before any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7)> WhenChanging( this TObj objectToMonitor, Expression> property1, @@ -581,13 +564,11 @@ public static RuntimeObservationFallback.WhenChanging(objectToMonitor, property5), RuntimeObservationFallback.WhenChanging(objectToMonitor, property6), RuntimeObservationFallback.WhenChanging(objectToMonitor, property7), - (v1, v2, v3, v4, v5, v6, v7) => (v1, v2, v3, v4, v5, v6, v7)); + static (v1, v2, v3, v4, v5, v6, v7) => (v1, v2, v3, v4, v5, v6, v7)); } #if NET8_0_OR_GREATER - /// - /// Observes 8 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 8 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -617,6 +598,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values before any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 @@ -650,9 +633,7 @@ public static [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes 8 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 8 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -674,6 +655,7 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values before any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 property8)> WhenChanging( this TObj objectToMonitor, Expression> property1, @@ -708,13 +690,11 @@ public static RuntimeObservationFallback.WhenChanging(objectToMonitor, property6), RuntimeObservationFallback.WhenChanging(objectToMonitor, property7), RuntimeObservationFallback.WhenChanging(objectToMonitor, property8), - (v1, v2, v3, v4, v5, v6, v7, v8) => (v1, v2, v3, v4, v5, v6, v7, v8)); + static (v1, v2, v3, v4, v5, v6, v7, v8) => (v1, v2, v3, v4, v5, v6, v7, v8)); } #if NET8_0_OR_GREATER - /// - /// Observes 9 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 9 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -747,6 +727,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values before any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 @@ -783,9 +765,7 @@ public static [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes 9 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 9 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -809,6 +789,7 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values before any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable<( T1 property1, T2 property2, @@ -855,13 +836,11 @@ public static RuntimeObservationFallback.WhenChanging(objectToMonitor, property7), RuntimeObservationFallback.WhenChanging(objectToMonitor, property8), RuntimeObservationFallback.WhenChanging(objectToMonitor, property9), - (v1, v2, v3, v4, v5, v6, v7, v8, v9) => (v1, v2, v3, v4, v5, v6, v7, v8, v9)); + static (v1, v2, v3, v4, v5, v6, v7, v8, v9) => (v1, v2, v3, v4, v5, v6, v7, v8, v9)); } #if NET8_0_OR_GREATER - /// - /// Observes 10 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 10 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -897,6 +876,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values before any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 @@ -936,9 +917,7 @@ public static [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes 10 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 10 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -964,6 +943,7 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values before any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable<( T1 property1, T2 property2, @@ -1014,13 +994,11 @@ public static RuntimeObservationFallback.WhenChanging(objectToMonitor, property8), RuntimeObservationFallback.WhenChanging(objectToMonitor, property9), RuntimeObservationFallback.WhenChanging(objectToMonitor, property10), - (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10)); + static (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10)); } #if NET8_0_OR_GREATER - /// - /// Observes 11 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 11 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -1059,6 +1037,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values before any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 @@ -1113,9 +1093,7 @@ public static [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes 11 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 11 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -1143,6 +1121,7 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values before any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable<( T1 property1, T2 property2, @@ -1197,13 +1176,11 @@ public static RuntimeObservationFallback.WhenChanging(objectToMonitor, property9), RuntimeObservationFallback.WhenChanging(objectToMonitor, property10), RuntimeObservationFallback.WhenChanging(objectToMonitor, property11), - (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11)); + static (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11)); } #if NET8_0_OR_GREATER - /// - /// Observes 12 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 12 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -1245,6 +1222,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values before any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 @@ -1303,9 +1282,7 @@ public static [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes 12 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 12 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -1335,6 +1312,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values before any of them changes. + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable<( T1 property1, T2 property2, @@ -1393,13 +1372,11 @@ public static RuntimeObservationFallback.WhenChanging(objectToMonitor, property10), RuntimeObservationFallback.WhenChanging(objectToMonitor, property11), RuntimeObservationFallback.WhenChanging(objectToMonitor, property12), - (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12)); + static (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12)); } #if NET8_0_OR_GREATER - /// - /// Observes 13 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 13 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -1444,6 +1421,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values before any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 @@ -1506,9 +1485,7 @@ public static [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes 13 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 13 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -1540,6 +1517,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values before any of them changes. + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable<( T1 property1, T2 property2, @@ -1602,14 +1581,12 @@ public static RuntimeObservationFallback.WhenChanging(objectToMonitor, property11), RuntimeObservationFallback.WhenChanging(objectToMonitor, property12), RuntimeObservationFallback.WhenChanging(objectToMonitor, property13), - (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) => + static (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13)); } #if NET8_0_OR_GREATER - /// - /// Observes 14 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 14 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -1657,6 +1634,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values before any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 @@ -1709,9 +1688,7 @@ public static [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes 14 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 14 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -1745,6 +1722,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values before any of them changes. + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable<( T1 property1, T2 property2, @@ -1811,14 +1790,12 @@ public static RuntimeObservationFallback.WhenChanging(objectToMonitor, property12), RuntimeObservationFallback.WhenChanging(objectToMonitor, property13), RuntimeObservationFallback.WhenChanging(objectToMonitor, property14), - (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) => + static (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14)); } #if NET8_0_OR_GREATER - /// - /// Observes 15 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 15 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -1869,6 +1846,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values before any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 @@ -1924,9 +1903,7 @@ public static [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes 15 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 15 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -1962,6 +1939,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values before any of them changes. + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable<( T1 property1, T2 property2, @@ -2032,14 +2011,12 @@ public static RuntimeObservationFallback.WhenChanging(objectToMonitor, property13), RuntimeObservationFallback.WhenChanging(objectToMonitor, property14), RuntimeObservationFallback.WhenChanging(objectToMonitor, property15), - (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) => + static (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15)); } #if NET8_0_OR_GREATER - /// - /// Observes 16 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 16 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -2093,6 +2070,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values before any of them changes. + [SuppressMessage("Design", "SST1472", Justification = "one selector per observed property; the parameter count is the shape of this overload")] + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] public static IObservable<(T1 property1, T2 property2, T3 property3, T4 property4, T5 property5, T6 property6, T7 property7, T8 @@ -2168,9 +2147,7 @@ public static [CallerLineNumber] int callerLineNumber = 0) where TObj : class #else - /// - /// Observes 16 properties of the specified object and emits their values as a tuple before any property changes. - /// + /// Observes 16 properties of the specified object and emits their values as a tuple before any property changes. /// The type of the object to monitor for property changes. /// The type of the first observed property value. /// The type of the second observed property value. @@ -2208,6 +2185,8 @@ public static /// The source file path of the caller. Auto-populated by the compiler. /// The source line number of the caller. Auto-populated by the compiler. /// An observable sequence that emits a tuple of all observed property values before any of them changes. + [SuppressMessage("Design", "SST1523", Justification = "one observation step per observed property; the length is the shape of this overload")] + [SuppressMessage("Design", "SST1472", Justification = "parameter count is inherent to the N-property dispatch stub and its CallerInfo contract")] public static IObservable<( T1 property1, T2 property2, @@ -2282,7 +2261,7 @@ public static RuntimeObservationFallback.WhenChanging(objectToMonitor, property14), RuntimeObservationFallback.WhenChanging(objectToMonitor, property15), RuntimeObservationFallback.WhenChanging(objectToMonitor, property16), - (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) => (v1, v2, v3, v4, v5, v6, v7, v8, + static (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) => (v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16)); } } diff --git a/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.cs b/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.cs index 21d414b..8223196 100644 --- a/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.cs +++ b/src/ReactiveUI.Binding/Mixins/ReactiveUIBindingExtensions.cs @@ -12,14 +12,6 @@ namespace ReactiveUI.Binding; /// Supports 1-16 property selectors for observation APIs (WhenChanged, WhenChanging, WhenAnyValue). /// [ExcludeFromCodeCoverage] -[SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "Deliberately large arity intrinsic to the N-argument binding/observable API surface.")] -[SuppressMessage( - "Critical Code Smell", - "S2360:Optional parameters should not be used", - Justification = "Optional toEvent and CallerInfo params are part of the dispatch stub contract; overloads here would shadow the generated overloads and break dispatch.")] public static partial class ReactiveUIBindingExtensions { /// diff --git a/src/ReactiveUI.Binding/ObservableForProperty/ExpressionChainSink.cs b/src/ReactiveUI.Binding/ObservableForProperty/ExpressionChainSink.cs index ff05c83..9669295 100644 --- a/src/ReactiveUI.Binding/ObservableForProperty/ExpressionChainSink.cs +++ b/src/ReactiveUI.Binding/ObservableForProperty/ExpressionChainSink.cs @@ -22,39 +22,25 @@ namespace ReactiveUI.Binding.ObservableForProperty; [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] public sealed class ExpressionChainSink : IObservable> { - /// - /// The root object of the chain. - /// + /// The root object of the chain. private readonly TSender? _source; - /// - /// The full expression surfaced on the emitted change. - /// + /// The full expression surfaced on the emitted change. private readonly Expression? _expression; - /// - /// The member-access links of the chain, in order. - /// + /// The member-access links of the chain, in order. private readonly Expression[] _links; - /// - /// Whether values are observed before they change. - /// + /// Whether values are observed before they change. private readonly bool _beforeChange; - /// - /// Whether the initial value is suppressed. - /// + /// Whether the initial value is suppressed. private readonly bool _skipInitial; - /// - /// Whether consecutive equal leaf values are suppressed. - /// + /// Whether consecutive equal leaf values are suppressed. private readonly bool _isDistinct; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The root object of the chain. /// The full expression surfaced on the emitted change. /// The member-access links of the chain, in order. @@ -88,75 +74,47 @@ public IDisposable Subscribe(IObserver> observe return sink; } - /// - /// The running state of one chain subscription. - /// + /// The running state of one chain subscription. [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] private sealed class Sink : IDisposable { - /// - /// Serializes chain mutations and emission. - /// - private readonly object _gate = new(); - - /// - /// The observer receiving the leaf observed changes. - /// + /// Serializes chain mutations and emission. + private readonly Lock _gate = new(); + + /// The observer receiving the leaf observed changes. private readonly IObserver> _downstream; - /// - /// The root object of the chain. - /// + /// The root object of the chain. private readonly TSender? _source; - /// - /// The full expression surfaced on the emitted change. - /// + /// The full expression surfaced on the emitted change. private readonly Expression? _expression; - /// - /// The member-access links of the chain, in order. - /// + /// The member-access links of the chain, in order. private readonly Expression[] _links; - /// - /// Whether values are observed before they change. - /// + /// Whether values are observed before they change. private readonly bool _beforeChange; - /// - /// Whether consecutive equal leaf values are suppressed. - /// + /// Whether consecutive equal leaf values are suppressed. private readonly bool _isDistinct; - /// - /// The per-link watchers. - /// + /// The per-link watchers. private readonly Level[] _levels; - /// - /// Whether the next raw emission should be skipped (skip-initial). - /// + /// Whether the next raw emission should be skipped (skip-initial). private bool _skipNext; - /// - /// The last emitted leaf value, used by the distinct gate. - /// + /// The last emitted leaf value, used by the distinct gate. private TValue _last = default!; - /// - /// Whether holds a value yet. - /// + /// Whether holds a value yet. private bool _hasLast; - /// - /// Latched once this chain subscription has been disposed. - /// + /// Latched once this chain subscription has been disposed. private bool _disposed; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The observer receiving the leaf observed changes. /// The root object of the chain. /// The full expression surfaced on the emitted change. @@ -181,19 +139,22 @@ public Sink( _isDistinct = isDistinct; _skipNext = skipInitial; _levels = new Level[links.Length]; - for (var i = 0; i < links.Length; i++) - { - _levels[i] = new Level(this, i, i == links.Length - 1); - } } - /// - /// Establishes the chain from the root value. - /// + /// Establishes the chain from the root value. + /// + /// The levels are built here rather than in the constructor: each one captures the sink, + /// and handing out mid-construction would expose a half-built object. + /// public void Run() { lock (_gate) { + for (var i = 0; i < _levels.Length; i++) + { + _levels[i] = new(this, i, i == _levels.Length - 1); + } + if (_links.Length == 0) { return; @@ -211,21 +172,18 @@ public void Dispose() _disposed = true; for (var i = 0; i < _levels.Length; i++) { - _levels[i].Dispose(); + // Null when disposed before Run built the chain. + _levels[i]?.Dispose(); } } } - /// - /// Sets the parent value of the level after . - /// + /// Sets the parent value of the level after . /// The level index that produced the value. /// The value the link produced (the parent for the next level). private void SetNextParent(int level, object? value) => _levels[level + 1].SetParent(value); - /// - /// Handles a leaf raw emission: applies skip-initial, the non-null-parent filter, the cast and the distinct gate. - /// + /// Handles a leaf raw emission: applies skip-initial, the non-null-parent filter, the cast and the distinct gate. /// Whether the leaf's parent was null. /// The leaf value when the parent is present. private void Emit(bool parentMissing, object? value) @@ -266,45 +224,29 @@ private void Emit(bool parentMissing, object? value) _downstream.OnNext(new ObservedChange(_source!, _expression, typed)); } - /// - /// A single chain link's watcher: re-subscribes on parent change and reads the link's value. - /// + /// A single chain link's watcher: re-subscribes on parent change and reads the link's value. [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] private sealed class Level : IDisposable { - /// - /// The owning chain sink. - /// + /// The owning chain sink. private readonly Sink _sink; - /// - /// This watcher's position in the chain. - /// + /// This watcher's position in the chain. private readonly int _index; - /// - /// Whether this is the final link in the chain. - /// + /// Whether this is the final link in the chain. private readonly bool _isLeaf; - /// - /// The current link-notification subscription; swapped on each re-parent. - /// + /// The current link-notification subscription; swapped on each re-parent. private readonly SerialDisposable _subscription = new(); - /// - /// This link's value fetcher, compiled once, or for an unsupported member. - /// + /// This link's value fetcher, compiled once, or for an unsupported member. private readonly Func? _getter; - /// - /// This link's index/argument array (non-null only for indexer links), cached once. - /// + /// This link's index/argument array (non-null only for indexer links), cached once. private readonly object?[]? _arguments; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The owning chain sink. /// This watcher's position in the chain. /// Whether this is the final link in the chain. @@ -318,9 +260,7 @@ public Level(Sink sink, int index, bool isLeaf) _arguments = sink._links[index].GetArgumentsArray(); } - /// - /// Re-establishes this watcher on a new parent value and propagates the current value downward. - /// + /// Re-establishes this watcher on a new parent value and propagates the current value downward. /// The object this link is read from. public void SetParent(object? parent) { @@ -343,7 +283,7 @@ public void SetParent(object? parent) // Kicker: propagate the current value immediately, then subscribe for updates. Push(ReadValue(parent)); - _subscription.Disposable = ReactiveNotifyPropertyChangedMixin + _subscription.Disposable = ReactiveNotifyPropertyChangedMixins .NotifyForProperty(parent, link, _sink._beforeChange) .Subscribe(new Observer(this)); } @@ -351,11 +291,9 @@ public void SetParent(object? parent) /// public void Dispose() => _subscription.Dispose(); - /// - /// Handles a notification for this link by re-reading the value and propagating it. - /// + /// Handles a notification for this link by re-reading the value and propagating it. /// The notification (its value is read via reflection). - public void OnNotification(IObservedChange change) + private void OnNotification(IObservedChange change) { lock (_sink._gate) { @@ -368,15 +306,11 @@ public void OnNotification(IObservedChange change) } } - /// - /// Forwards a link-subscription error to the downstream observer. - /// + /// Forwards a link-subscription error to the downstream observer. /// The error to forward. - public void ForwardError(Exception error) => _sink._downstream.OnError(error); + private void ForwardError(Exception error) => _sink._downstream.OnError(error); - /// - /// Reads the current value of this link from a parent using the cached fetcher. - /// + /// Reads the current value of this link from a parent using the cached fetcher. /// The object the link is read from. /// The link's current value, or the default when the parent is null. private object? ReadValue(object? parent) @@ -391,9 +325,7 @@ public void OnNotification(IObservedChange change) : new ObservedChange(parent, _sink._links[_index], null).GetValueOrDefault(); } - /// - /// Forwards this link's value to the next level, or emits it at the leaf. - /// + /// Forwards this link's value to the next level, or emits it at the leaf. /// The value this link produced. private void Push(object? value) { @@ -407,19 +339,13 @@ private void Push(object? value) } } - /// - /// Forwards a link's notifications back into the level. - /// + /// Forwards a link's notifications back into the level. private sealed class Observer : IObserver> { - /// - /// The owning level. - /// + /// The owning level. private readonly Level _level; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The owning level. public Observer(Level level) => _level = level; diff --git a/src/ReactiveUI.Binding/ObservableForProperty/INPCObservableForProperty.cs b/src/ReactiveUI.Binding/ObservableForProperty/INPCObservableForProperty.cs index b758477..44a0270 100644 --- a/src/ReactiveUI.Binding/ObservableForProperty/INPCObservableForProperty.cs +++ b/src/ReactiveUI.Binding/ObservableForProperty/INPCObservableForProperty.cs @@ -8,18 +8,10 @@ namespace ReactiveUI.Binding.ObservableForProperty; -/// -/// Generates Observables based on observing INotifyPropertyChanged objects. -/// -[SuppressMessage( - "Minor Code Smell", - "S101:Types should be named in PascalCase", - Justification = "INPC is an established acronym for INotifyPropertyChanged and matches the ReactiveUI public API name.")] +/// Generates Observables based on observing INotifyPropertyChanged objects. public class INPCObservableForProperty : ICreatesObservableForProperty { - /// - /// The affinity returned when the target type implements the relevant notification interface. - /// + /// The affinity returned when the target type implements the relevant notification interface. private static readonly int SupportedAffinity = BindingAffinity.Explicit; /// @@ -46,7 +38,7 @@ public int GetAffinityForObject(Type type, string propertyName, bool beforeChang // wires the event, filters by name, and emits the observed change directly. if ((beforeChanged && sender is INotifyPropertyChanging) || sender is INotifyPropertyChanged) { - var expectedName = expression.NodeType == ExpressionType.Index ? propertyName + "[]" : propertyName; + var expectedName = expression.NodeType == ExpressionType.Index ? $"{propertyName}[]" : propertyName; return new NotifyPropertyChangedObservable(sender, expression, expectedName, beforeChanged); } diff --git a/src/ReactiveUI.Binding/ObservableForProperty/ObservableForPropertySink.cs b/src/ReactiveUI.Binding/ObservableForProperty/ObservableForPropertySink.cs index 6310df6..19ac0a5 100644 --- a/src/ReactiveUI.Binding/ObservableForProperty/ObservableForPropertySink.cs +++ b/src/ReactiveUI.Binding/ObservableForProperty/ObservableForPropertySink.cs @@ -17,39 +17,25 @@ namespace ReactiveUI.Binding.ObservableForProperty; [EditorBrowsable(EditorBrowsableState.Never)] public sealed class ObservableForPropertySink : IObservable> { - /// - /// The observed object surfaced on the emitted change. - /// + /// The observed object surfaced on the emitted change. private readonly TSender _sender; - /// - /// The expression surfaced on the emitted change. - /// + /// The expression surfaced on the emitted change. private readonly Expression _expression; - /// - /// The underlying change-notification source (a notification re-reads the value). - /// + /// The underlying change-notification source (a notification re-reads the value). private readonly IObservable> _notifications; - /// - /// Reads the current property value from the sender. - /// + /// Reads the current property value from the sender. private readonly Func _readValue; - /// - /// When , the current value is not emitted on subscribe. - /// + /// When , the current value is not emitted on subscribe. private readonly bool _skipInitial; - /// - /// When , consecutive equal values are suppressed. - /// + /// When , consecutive equal values are suppressed. private readonly bool _isDistinct; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The observed object surfaced on the emitted change. /// The expression surfaced on the emitted change. /// The underlying change-notification source. @@ -84,71 +70,41 @@ public IDisposable Subscribe(IObserver> observe return sink.Run(_notifications, _skipInitial); } - /// - /// Reads the property value on each notification and forwards it as an observed change. - /// - private sealed class Sink : IObserver> - { - /// - /// The observer receiving observed changes. - /// - private readonly IObserver> _downstream; - - /// - /// The observed object. - /// - private readonly TSender _sender; - - /// - /// The expression surfaced on the observed change. - /// - private readonly Expression _expression; - - /// - /// Reads the current property value from the sender. - /// - private readonly Func _readValue; - - /// - /// Whether consecutive equal values are suppressed. - /// - private readonly bool _isDistinct; - - /// - /// The last emitted value, used by the distinct gate. - /// - private TValue _last = default!; - - /// - /// Whether holds a value yet. - /// - private bool _hasLast; - - /// - /// Initializes a new instance of the class. - /// - /// The observer receiving observed changes. - /// The observed object. - /// The expression surfaced on the observed change. - /// Reads the current property value. - /// Whether consecutive equal values are suppressed. - public Sink( + /// Reads the property value on each notification and forwards it as an observed change. + /// The observer receiving observed changes. + /// The observed object. + /// The expression surfaced on the observed change. + /// Reads the current property value. + /// Whether consecutive equal values are suppressed. + private sealed class Sink( IObserver> downstream, TSender sender, Expression expression, Func readValue, - bool isDistinct) - { - _downstream = downstream; - _sender = sender; - _expression = expression; - _readValue = readValue; - _isDistinct = isDistinct; - } + bool isDistinct) : IObserver> + { + /// The observer receiving observed changes. + private readonly IObserver> _downstream = downstream; + + /// The observed object. + private readonly TSender _sender = sender; + + /// The expression surfaced on the observed change. + private readonly Expression _expression = expression; + + /// Reads the current property value from the sender. + private readonly Func _readValue = readValue; + + /// Whether consecutive equal values are suppressed. + private readonly bool _isDistinct = isDistinct; + + /// The last emitted value, used by the distinct gate. + private TValue _last = default!; + + /// Whether holds a value yet. + private bool _hasLast; - /// - /// Optionally emits the current value, then subscribes to the notification source. - /// + /// Optionally emits the current value, then subscribes to the notification source. /// The change-notification source. /// When , the current value is not emitted on subscribe. /// The notification-source subscription. @@ -171,9 +127,7 @@ public IDisposable Run(IObservable> notificatio /// public void OnCompleted() => _downstream.OnCompleted(); - /// - /// Reads the current property value and forwards it as an observed change, honoring the distinct gate. - /// + /// Reads the current property value and forwards it as an observed change, honoring the distinct gate. private void Emit() { TValue current; diff --git a/src/ReactiveUI.Binding/ObservableForProperty/ObservedChangedMixin.cs b/src/ReactiveUI.Binding/ObservableForProperty/ObservedChangedMixin.cs deleted file mode 100644 index a0b6ed5..0000000 --- a/src/ReactiveUI.Binding/ObservableForProperty/ObservedChangedMixin.cs +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) 2019-2026 ReactiveUI Association Incorporated. All rights reserved. -// ReactiveUI Association Incorporated licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using ReactiveUI.Binding.Expressions; -using ReactiveUI.Binding.Observables; - -namespace ReactiveUI.Binding.ObservableForProperty; - -/// -/// A collection of helpers for . -/// -public static class ObservedChangedMixin -{ - /// - /// Returns the name of a property which has been changed. - /// - /// The sender type. - /// The value type. - /// The observed change. - /// The name of the property which has changed. - public static string GetPropertyName(this IObservedChange item) - { - ArgumentExceptionHelper.ThrowIfNull(item); - return Reflection.ExpressionToPropertyNames(item.Expression); - } - - /// - /// Returns the current value of a property given a notification that it has changed. - /// - /// The sender. - /// The changed value. - /// The observed change instance to get the value of. - /// The current value of the property. - [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] - public static TValue GetValue(this IObservedChange item) - { - ArgumentExceptionHelper.ThrowIfNull(item); - - if (!item.TryGetValue(out var returnValue)) - { - throw new InvalidOperationException($"One of the properties in the expression '{item.GetPropertyName()}' was null"); - } - - return returnValue; - } - - /// - /// Returns the current value of a property given a notification that it has changed, - /// or the default value if the chain cannot be resolved. - /// - /// The sender. - /// The changed value. - /// The observed change instance to get the value of. - /// The current value of the property, or default. - [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] - public static TValue? GetValueOrDefault(this IObservedChange item) - { - ArgumentExceptionHelper.ThrowIfNull(item); - return !item.TryGetValue(out var returnValue) ? default : returnValue; - } - - /// - /// Given a stream of notification changes, this method will convert - /// the property changes to the current value of the property. - /// - /// The sender type. - /// The value type. - /// The change notification stream to get the values of. - /// An Observable representing the stream of current values. - [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] - public static IObservable Value(this IObservable> item) => - new SelectObservable, TValue>(item, GetValue); - - /// - /// Attempts to return the current value of a property given a notification that it has changed. - /// - /// The sender type. - /// The value type. - /// The observed change instance to get the value of. - /// The value of the property expression. - /// True if the entire expression was able to be followed, false otherwise. - [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] - internal static bool TryGetValue( - this IObservedChange item, - out TValue changeValue) - { - if (Equals(item.Value, default(TValue))) - { - return Reflection.TryGetValueForPropertyChain( - out changeValue, - item.Sender, - item.Expression!.GetExpressionChain()); - } - - changeValue = item.Value; - return true; - } - - /// - /// Given a fully filled-out IObservedChange object, SetValueToProperty - /// will apply it to the specified object. - /// - /// The sender type. - /// The value type. - /// The target type. - /// The observed change instance to use as a value to apply. - /// The target object to apply the change to. - /// The target property to apply the change to. - [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] - internal static void SetValueToProperty( - this IObservedChange item, - TTarget target, - Expression> property) - { - if (target is null) - { - return; - } - - Reflection.TrySetValueToPropertyChain( - target, - Reflection.Rewrite(property.Body).GetExpressionChain(), - item.GetValue()); - } -} diff --git a/src/ReactiveUI.Binding/ObservableForProperty/ObservedChangedMixins.cs b/src/ReactiveUI.Binding/ObservableForProperty/ObservedChangedMixins.cs new file mode 100644 index 0000000..d4255db --- /dev/null +++ b/src/ReactiveUI.Binding/ObservableForProperty/ObservedChangedMixins.cs @@ -0,0 +1,111 @@ +// Copyright (c) 2019-2026 ReactiveUI Association Incorporated. All rights reserved. +// ReactiveUI Association Incorporated licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +using ReactiveUI.Binding.Expressions; +using ReactiveUI.Binding.Observables; + +namespace ReactiveUI.Binding.ObservableForProperty; + +/// A collection of helpers for . +public static class ObservedChangedMixins +{ + /// Provides Value extension members for . + /// The sender type. + /// The value type. + /// The change notification stream to get the values of. + extension(IObservable> stream) + { + /// + /// Given a stream of notification changes, this method will convert + /// the property changes to the current value of the property. + /// + /// An Observable representing the stream of current values. + [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] + public IObservable Value() => + new SelectObservable, TValue>(stream, GetValue); + } + + /// Provides value-access extension members for . + /// The sender type. + /// The value type. + /// The observed change. + extension(IObservedChange item) + { + /// Returns the name of a property which has been changed. + /// The name of the property which has changed. + public string GetPropertyName() + { + ArgumentExceptionHelper.ThrowIfNull(item); + return Reflection.ExpressionToPropertyNames(item.Expression); + } + + /// Returns the current value of a property given a notification that it has changed. + /// The current value of the property. + [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] + public TValue GetValue() + { + ArgumentExceptionHelper.ThrowIfNull(item); + + if (!item.TryGetValue(out var returnValue)) + { + throw new InvalidOperationException($"One of the properties in the expression '{item.GetPropertyName()}' was null"); + } + + return returnValue; + } + + /// + /// Returns the current value of a property given a notification that it has changed, + /// or the default value if the chain cannot be resolved. + /// + /// The current value of the property, or default. + [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] + public TValue? GetValueOrDefault() + { + ArgumentExceptionHelper.ThrowIfNull(item); + return !item.TryGetValue(out var returnValue) ? default : returnValue; + } + + /// Attempts to return the current value of a property given a notification that it has changed. + /// The value of the property expression. + /// True if the entire expression was able to be followed, false otherwise. + [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] + internal bool TryGetValue( + out TValue changeValue) + { + // TValue is unconstrained, so default(TValue) is maybe-null while the comparer's parameter is not + // annotated; the comparer handles a null operand, so the state is suppressed rather than guarded. + if (EqualityComparer.Default.Equals(item.Value, default!)) + { + return Reflection.TryGetValueForPropertyChain( + out changeValue, + item.Sender, + item.Expression!.GetExpressionChain()); + } + + changeValue = item.Value; + return true; + } + + /// Given a fully filled-out IObservedChange object, SetValueToProperty will apply it to the specified object. + /// The target type. + /// The target object to apply the change to. + /// The target property to apply the change to. + [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] + internal void SetValueToProperty( + TTarget target, + Expression> property) + { + if (target is null) + { + return; + } + + _ = Reflection.TrySetValueToPropertyChain( + target, + Reflection.Rewrite(property.Body).GetExpressionChain(), + item.GetValue()); + } + } +} diff --git a/src/ReactiveUI.Binding/ObservableForProperty/POCOObservableForProperty.cs b/src/ReactiveUI.Binding/ObservableForProperty/POCOObservableForProperty.cs index e88f2f8..bbb92f8 100644 --- a/src/ReactiveUI.Binding/ObservableForProperty/POCOObservableForProperty.cs +++ b/src/ReactiveUI.Binding/ObservableForProperty/POCOObservableForProperty.cs @@ -11,15 +11,9 @@ namespace ReactiveUI.Binding.ObservableForProperty; /// Final fallback implementation for observation when no observable mechanism is available. /// Emits exactly one value (the current value at subscription time) and then never emits again. /// -[SuppressMessage( - "Minor Code Smell", - "S101:Types should be named in PascalCase", - Justification = "POCO is an established acronym (Plain Old CLR Object) and matches the ReactiveUI public API name.")] public sealed class POCOObservableForProperty : ICreatesObservableForProperty { - /// - /// Tracks which (type, property) pairs have already emitted a POCO warning to avoid duplicate messages. - /// + /// Tracks which (type, property) pairs have already emitted a POCO warning to avoid duplicate messages. private static readonly ConcurrentDictionary<(Type Type, string PropertyName), byte> HasWarned = new(); /// diff --git a/src/ReactiveUI.Binding/ObservableForProperty/ReactiveNotifyPropertyChangedMixin.cs b/src/ReactiveUI.Binding/ObservableForProperty/ReactiveNotifyPropertyChangedMixin.cs deleted file mode 100644 index c38f119..0000000 --- a/src/ReactiveUI.Binding/ObservableForProperty/ReactiveNotifyPropertyChangedMixin.cs +++ /dev/null @@ -1,328 +0,0 @@ -// Copyright (c) 2019-2026 ReactiveUI Association Incorporated. All rights reserved. -// ReactiveUI Association Incorporated licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System.ComponentModel; -using System.Linq; -using ReactiveUI.Binding.Expressions; -using ReactiveUI.Binding.Observables; - -namespace ReactiveUI.Binding.ObservableForProperty; - -/// -/// Extension methods for property change observation using expression chains. -/// This is a runtime fallback bridge class — the source generator produces optimized -/// code that bypasses this entirely at compile time. -/// -[ExcludeFromCodeCoverage] -[EditorBrowsable(EditorBrowsableState.Never)] -[RequiresUnreferencedCode( - "Creating Expressions requires unreferenced code because the members being referenced by the Expression may be trimmed.")] -[SuppressMessage( - "Major Code Smell", - "S4018:Generic methods should provide type parameter for type inference", - Justification = "The type parameter denotes the target type (value/control/view), supplied explicitly by callers; it is not derivable from the arguments. Public API.")] -public static class ReactiveNotifyPropertyChangedMixin -{ - /// - /// MRU cache that maps (sender type, property name, before-change flag) to the best - /// implementation for that combination. - /// - private static readonly MemoizingMRUCache< - (Type senderType, string propertyName, bool beforeChange), - ICreatesObservableForProperty?> - NotifyFactoryCache = - new( - (t, _) => AppLocator.Current.GetServices() - .Aggregate( - (score: 0, binding: (ICreatesObservableForProperty?)null), - (acc, x) => - { - var score = x.GetAffinityForObject(t.senderType, t.propertyName, t.beforeChange); - return score > acc.score ? (score, x) : acc; - }).binding, - 64); - - /// - /// ObservableForProperty by name, observing after-change, emitting the initial value, with distinct filtering. - /// - /// The sender type. - /// The value type. - /// The source object to observe properties of. - /// The property name to observe. - /// An Observable representing the property change notifications for the given property name. - [RequiresUnreferencedCode( - "Creating Expressions requires unreferenced code because the members being referenced by the Expression may be trimmed.")] - public static IObservable> ObservableForProperty( - this TSender? item, - string propertyName) => - ObservableForProperty(item, propertyName, false, true, true); - - /// - /// ObservableForProperty by name, observing after-change with distinct filtering and a configurable initial value. - /// - /// The sender type. - /// The value type. - /// The source object to observe properties of. - /// The property name to observe. - /// If true, the Observable will not notify with the initial value. - /// An Observable representing the property change notifications for the given property name. - [RequiresUnreferencedCode( - "Creating Expressions requires unreferenced code because the members being referenced by the Expression may be trimmed.")] - public static IObservable> ObservableForProperty( - this TSender? item, - string propertyName, - bool skipInitial) => - ObservableForProperty(item, propertyName, false, skipInitial, true); - - /// - /// ObservableForProperty returns an Observable representing the - /// property change notifications for a specific property on an object. - /// This overload avoids expression tree analysis by using a property name string. - /// - /// The sender type. - /// The value type. - /// The source object to observe properties of. - /// The property name to observe. - /// If true, the Observable will notify immediately before a property is going to change. - /// If true, the Observable will not notify with the initial value. - /// If set to true, values are filtered with DistinctUntilChanged. - /// An Observable representing the property change notifications for the given property name. - [RequiresUnreferencedCode( - "Creating Expressions requires unreferenced code because the members being referenced by the Expression may be trimmed.")] - public static IObservable> ObservableForProperty( - this TSender? item, - string propertyName, - bool beforeChange, - bool skipInitial, - bool isDistinct) - { - ArgumentExceptionHelper.ThrowIfNull(item); - ArgumentExceptionHelper.ThrowIfNull(propertyName); - - var parameter = Expression.Parameter(typeof(TSender), "x"); - Expression expr; - try - { - expr = Expression.Property(parameter, propertyName); - } - catch - { - expr = parameter; - } - - var factory = NotifyFactoryCache.Get((item!.GetType(), propertyName, beforeChange)) - ?? throw new InvalidOperationException( - $"Could not find a ICreatesObservableForProperty for {item.GetType()} property {propertyName}. " + - "This should never happen, your service locator is probably broken. " + - "Please make sure you have registered ICreatesObservableForProperty implementations."); - - static TValue GetCurrentValue(object sender, string name) - { - var t = sender.GetType(); - var prop = t.GetProperty( - name, - System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.FlattenHierarchy); - if (prop is null) - { - return default!; - } - - var val = prop.GetValue(sender); - if (val is null) - { - return default!; - } - - return val is TValue tv ? tv : (TValue)val; - } - - // Single fused sink: emits the initial value (unless skipped), then re-reads and emits on each - // notification, applying the distinct gate inline. - var notifications = factory.GetNotificationForProperty(item!, expr, propertyName, beforeChange); - return new ObservableForPropertySink( - item!, - expr, - notifications, - () => GetCurrentValue(item!, propertyName), - skipInitial, - isDistinct); - } - - /// - /// ObservableForProperty by expression, observing after-change, emitting the initial value, with distinct filtering. - /// - /// The sender type. - /// The value type. - /// The source object to observe properties of. - /// An Expression representing the property. - /// An Observable representing the property change notifications for the given property. - [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] - public static IObservable> ObservableForProperty( - this TSender? item, - Expression> property) => - ObservableForProperty(item, property, false, true, true); - - /// - /// ObservableForProperty by expression, observing after-change with distinct filtering and a configurable initial value. - /// - /// The sender type. - /// The value type. - /// The source object to observe properties of. - /// An Expression representing the property. - /// If true, the Observable will not notify with the initial value. - /// An Observable representing the property change notifications for the given property. - [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] - public static IObservable> ObservableForProperty( - this TSender? item, - Expression> property, - bool skipInitial) => - ObservableForProperty(item, property, false, skipInitial, true); - - /// - /// ObservableForProperty returns an Observable representing the - /// property change notifications for a specific property on an object. - /// This method uses expression trees to identify the property. - /// - /// The sender type. - /// The value type. - /// The source object to observe properties of. - /// An Expression representing the property. - /// If true, the Observable will notify immediately before a property is going to change. - /// If true, the Observable will not notify with the initial value. - /// If set to true, values are filtered with DistinctUntilChanged. - /// An Observable representing the property change notifications for the given property. - [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] - public static IObservable> ObservableForProperty( - this TSender? item, - Expression> property, - bool beforeChange, - bool skipInitial, - bool isDistinct) - { - ArgumentExceptionHelper.ThrowIfNull(property); - - return SubscribeToExpressionChain( - item, - property.Body, - beforeChange, - skipInitial, - isDistinct); - } - - /// - /// Subscribes to an expression chain, observing after-change, emitting the initial value, with distinct filtering. - /// - /// The type of the origin of the expression chain. - /// The end value we want to subscribe to. - /// The object where we start the chain. - /// An expression which will point towards the property. - /// An observable which notifies about observed changes. - [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] - public static IObservable> SubscribeToExpressionChain( - this TSender? source, - Expression? expression) => - SubscribeToExpressionChain(source, expression, false, true, true); - - /// - /// Subscribes to an expression chain, observing after-change with distinct filtering and a configurable initial value. - /// - /// The type of the origin of the expression chain. - /// The end value we want to subscribe to. - /// The object where we start the chain. - /// An expression which will point towards the property. - /// If we don't want to get a notification about the default value of the property. - /// An observable which notifies about observed changes. - [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] - public static IObservable> SubscribeToExpressionChain( - this TSender? source, - Expression? expression, - bool skipInitial) => - SubscribeToExpressionChain(source, expression, false, skipInitial, true); - - /// - /// Creates an observable which will subscribe to each property and sub-property - /// specified in the Expression, providing updates to the last value in the chain. - /// - /// The type of the origin of the expression chain. - /// The end value we want to subscribe to. - /// The object where we start the chain. - /// An expression which will point towards the property. - /// If we are interested in notifications before the property value is changed. - /// If we don't want to get a notification about the default value of the property. - /// If set to true, values are filtered with DistinctUntilChanged. - /// An observable which notifies about observed changes. - [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] - public static IObservable> SubscribeToExpressionChain( - this TSender? source, - Expression? expression, - bool beforeChange, - bool skipInitial, - bool isDistinct) - { - // Single fused switching engine: one watcher per link, re-subscribing deeper links when an - // intermediate value changes, with skip-initial, the non-null-parent filter, the cast to TValue, - // and the distinct gate applied inline. - var links = Reflection.Rewrite(expression).GetExpressionChain().ToArray(); - return new ExpressionChainSink(source, expression, links, beforeChange, skipInitial, isDistinct); - } - - /// - /// Creates an observable that tracks nested property changes for a single link in an expression chain. - /// - /// The expression representing the current property in the chain. - /// The observed change from the previous link in the chain. - /// If , subscribes to before-change notifications. - /// An observable of observed changes for the current property link. - [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] - internal static IObservable> NestedObservedChanges( - Expression expression, - IObservedChange sourceChange, - bool beforeChange) - { - var kicker = new ObservedChange(sourceChange.Value, expression, default); - - if (sourceChange.Value is null) - { - return new ReturnObservable>(kicker); - } - - return new SelectObservable, IObservedChange>( - new StartWithObservable>( - NotifyForProperty(sourceChange.Value, expression, beforeChange), - kicker), - static x => new ObservedChange(x.Sender, x.Expression, x.GetValueOrDefault())); - } - - /// - /// Gets property change notifications for a single property on an object by resolving the - /// best implementation from the service locator. - /// - /// The object to observe. - /// The expression identifying the property to observe. - /// If , subscribes to before-change notifications. - /// An observable of observed changes for the property. - [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] - internal static IObservable> NotifyForProperty( - object sender, - Expression expression, - bool beforeChange) - { - ArgumentExceptionHelper.ThrowIfNull(expression); - - var memberInfo = expression.GetMemberInfo() ?? throw new ArgumentException( - "The expression does not have valid member info", - nameof(expression)); - var propertyName = memberInfo.Name; - var result = NotifyFactoryCache.Get((sender.GetType(), propertyName, beforeChange)); - - return result switch - { - null => throw new InvalidOperationException( - $"Could not find a ICreatesObservableForProperty for {sender.GetType()} property {propertyName}. " + - "This should never happen, your service locator is probably broken. " + - "Please make sure you have registered ICreatesObservableForProperty implementations."), - _ => result.GetNotificationForProperty(sender, expression, propertyName, beforeChange) - }; - } -} diff --git a/src/ReactiveUI.Binding/ObservableForProperty/ReactiveNotifyPropertyChangedMixins.cs b/src/ReactiveUI.Binding/ObservableForProperty/ReactiveNotifyPropertyChangedMixins.cs new file mode 100644 index 0000000..65502a3 --- /dev/null +++ b/src/ReactiveUI.Binding/ObservableForProperty/ReactiveNotifyPropertyChangedMixins.cs @@ -0,0 +1,300 @@ +// Copyright (c) 2019-2026 ReactiveUI Association Incorporated. All rights reserved. +// ReactiveUI Association Incorporated licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +using System.ComponentModel; +using ReactiveUI.Binding.Expressions; +using ReactiveUI.Binding.Observables; + +namespace ReactiveUI.Binding.ObservableForProperty; + +/// +/// Extension methods for property change observation using expression chains. +/// This is a runtime fallback bridge class — the source generator produces optimized +/// code that bypasses this entirely at compile time. +/// +[ExcludeFromCodeCoverage] +[EditorBrowsable(EditorBrowsableState.Never)] +[RequiresUnreferencedCode( + "Creating Expressions requires unreferenced code because the members being referenced by the Expression may be trimmed.")] +public static class ReactiveNotifyPropertyChangedMixins +{ + /// Number of resolved factories kept in the MRU cache. + private const int NotifyFactoryCacheSize = 64; + + /// Appended to the "no factory found" message; the only way to hit it is a misconfigured locator. + private const string BrokenLocatorAdvice = + "This should never happen, your service locator is probably broken. Please make sure you have registered ICreatesObservableForProperty implementations."; + + /// MRU cache that maps (sender type, property name, before-change flag) to the best implementation for that combination. + private static readonly MemoizingMRUCache< + (Type senderType, string propertyName, bool beforeChange), + ICreatesObservableForProperty?> + NotifyFactoryCache = + new( + static (t, _) => + { + var bestScore = 0; + ICreatesObservableForProperty? best = null; + foreach (var candidate in AppLocator.Current.GetServices()) + { + var score = candidate.GetAffinityForObject(t.senderType, t.propertyName, t.beforeChange); + if (score > bestScore) + { + bestScore = score; + best = candidate; + } + } + + return best; + }, + NotifyFactoryCacheSize); + + /// Provides ObservableForProperty extension members for . + /// The sender type. + /// The source object to observe properties of. + extension(TSender? item) + { + /// ObservableForProperty by name, observing after-change, emitting the initial value, with distinct filtering. + /// The value type. + /// The property name to observe. + /// An Observable representing the property change notifications for the given property name. + [SuppressMessage("Design", "SST2307:Type parameters should be inferable", Justification = "Specified explicitly by the caller; it identifies the observed shape.")] + [RequiresUnreferencedCode( + "Creating Expressions requires unreferenced code because the members being referenced by the Expression may be trimmed.")] + public IObservable> ObservableForProperty( + string propertyName) => + ObservableForProperty(item, propertyName, false, true, true); + + /// ObservableForProperty by name, observing after-change with distinct filtering and a configurable initial value. + /// The value type. + /// The property name to observe. + /// If true, the Observable will not notify with the initial value. + /// An Observable representing the property change notifications for the given property name. + [SuppressMessage("Design", "SST2307:Type parameters should be inferable", Justification = "Specified explicitly by the caller; it identifies the observed shape.")] + [RequiresUnreferencedCode( + "Creating Expressions requires unreferenced code because the members being referenced by the Expression may be trimmed.")] + public IObservable> ObservableForProperty( + string propertyName, + bool skipInitial) => + ObservableForProperty(item, propertyName, false, skipInitial, true); + + /// + /// ObservableForProperty returns an Observable representing the + /// property change notifications for a specific property on an object. + /// This overload avoids expression tree analysis by using a property name string. + /// + /// The value type. + /// The property name to observe. + /// If true, the Observable will notify immediately before a property is going to change. + /// If true, the Observable will not notify with the initial value. + /// If set to true, values are filtered with DistinctUntilChanged. + /// An Observable representing the property change notifications for the given property name. + [SuppressMessage("Design", "SST2307:Type parameters should be inferable", Justification = "Specified explicitly by the caller; it identifies the observed shape.")] + [RequiresUnreferencedCode( + "Creating Expressions requires unreferenced code because the members being referenced by the Expression may be trimmed.")] + public IObservable> ObservableForProperty( + string propertyName, + bool beforeChange, + bool skipInitial, + bool isDistinct) + { + ArgumentExceptionHelper.ThrowIfNull(item); + ArgumentExceptionHelper.ThrowIfNull(propertyName); + + var parameter = Expression.Parameter(typeof(TSender), "x"); + Expression expr; + try + { + expr = Expression.Property(parameter, propertyName); + } + catch + { + expr = parameter; + } + + var factory = NotifyFactoryCache.Get((item!.GetType(), propertyName, beforeChange)) + ?? throw new InvalidOperationException( + $"Could not find a ICreatesObservableForProperty for {item.GetType()} property {propertyName}. {BrokenLocatorAdvice}"); + + static TValue GetCurrentValue(object sender, string name) + { + var t = sender.GetType(); + var prop = t.GetProperty( + name, + System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.FlattenHierarchy); + if (prop is null) + { + return default!; + } + + var val = prop.GetValue(sender); + if (val is null) + { + return default!; + } + + return val is TValue tv ? tv : (TValue)val; + } + + // Single fused sink: emits the initial value (unless skipped), then re-reads and emits on each + // notification, applying the distinct gate inline. + var notifications = factory.GetNotificationForProperty(item!, expr, propertyName, beforeChange); + return new ObservableForPropertySink( + item!, + expr, + notifications, + () => GetCurrentValue(item!, propertyName), + skipInitial, + isDistinct); + } + + /// ObservableForProperty by expression, observing after-change, emitting the initial value, with distinct filtering. + /// The value type. + /// An Expression representing the property. + /// An Observable representing the property change notifications for the given property. + [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] + public IObservable> ObservableForProperty( + Expression> property) => + ObservableForProperty(item, property, false, true, true); + + /// ObservableForProperty by expression, observing after-change with distinct filtering and a configurable initial value. + /// The value type. + /// An Expression representing the property. + /// If true, the Observable will not notify with the initial value. + /// An Observable representing the property change notifications for the given property. + [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] + public IObservable> ObservableForProperty( + Expression> property, + bool skipInitial) => + ObservableForProperty(item, property, false, skipInitial, true); + + /// + /// ObservableForProperty returns an Observable representing the + /// property change notifications for a specific property on an object. + /// This method uses expression trees to identify the property. + /// + /// The value type. + /// An Expression representing the property. + /// If true, the Observable will notify immediately before a property is going to change. + /// If true, the Observable will not notify with the initial value. + /// If set to true, values are filtered with DistinctUntilChanged. + /// An Observable representing the property change notifications for the given property. + [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] + public IObservable> ObservableForProperty( + Expression> property, + bool beforeChange, + bool skipInitial, + bool isDistinct) + { + ArgumentExceptionHelper.ThrowIfNull(property); + + return SubscribeToExpressionChain( + item, + property.Body, + beforeChange, + skipInitial, + isDistinct); + } + + /// Subscribes to an expression chain, observing after-change, emitting the initial value, with distinct filtering. + /// The end value we want to subscribe to. + /// An expression which will point towards the property. + /// An observable which notifies about observed changes. + [SuppressMessage("Design", "SST2307:Type parameters should be inferable", Justification = "Specified explicitly by the caller; it identifies the observed shape.")] + [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] + public IObservable> SubscribeToExpressionChain( + Expression? expression) => + SubscribeToExpressionChain(item, expression, false, true, true); + + /// Subscribes to an expression chain, observing after-change with distinct filtering and a configurable initial value. + /// The end value we want to subscribe to. + /// An expression which will point towards the property. + /// If we don't want to get a notification about the default value of the property. + /// An observable which notifies about observed changes. + [SuppressMessage("Design", "SST2307:Type parameters should be inferable", Justification = "Specified explicitly by the caller; it identifies the observed shape.")] + [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] + public IObservable> SubscribeToExpressionChain( + Expression? expression, + bool skipInitial) => + SubscribeToExpressionChain(item, expression, false, skipInitial, true); + + /// + /// Creates an observable which will subscribe to each property and sub-property + /// specified in the Expression, providing updates to the last value in the chain. + /// + /// The end value we want to subscribe to. + /// An expression which will point towards the property. + /// If we are interested in notifications before the property value is changed. + /// If we don't want to get a notification about the default value of the property. + /// If set to true, values are filtered with DistinctUntilChanged. + /// An observable which notifies about observed changes. + [SuppressMessage("Design", "SST2307:Type parameters should be inferable", Justification = "Specified explicitly by the caller; it identifies the observed shape.")] + [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] + public IObservable> SubscribeToExpressionChain( + Expression? expression, + bool beforeChange, + bool skipInitial, + bool isDistinct) + { + // Single fused switching engine: one watcher per link, re-subscribing deeper links when an + // intermediate value changes, with skip-initial, the non-null-parent filter, the cast to TValue, + // and the distinct gate applied inline. + var links = new List(Reflection.Rewrite(expression).GetExpressionChain()).ToArray(); + return new ExpressionChainSink(item, expression, links, beforeChange, skipInitial, isDistinct); + } + + } + + /// Creates an observable that tracks nested property changes for a single link in an expression chain. + /// The expression representing the current property in the chain. + /// The observed change from the previous link in the chain. + /// If , subscribes to before-change notifications. + /// An observable of observed changes for the current property link. + [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] + internal static IObservable> NestedObservedChanges( + Expression expression, + IObservedChange sourceChange, + bool beforeChange) + { + var kicker = new ObservedChange(sourceChange.Value, expression, default); + + return sourceChange.Value is null + ? new ReturnObservable>(kicker) + : new SelectObservable, IObservedChange>( + new StartWithObservable>( + NotifyForProperty(sourceChange.Value, expression, beforeChange), + kicker), + static x => new ObservedChange(x.Sender, x.Expression, x.GetValueOrDefault())); + } + + /// + /// Gets property change notifications for a single property on an object by resolving the + /// best implementation from the service locator. + /// + /// The object to observe. + /// The expression identifying the property to observe. + /// If , subscribes to before-change notifications. + /// An observable of observed changes for the property. + [RequiresUnreferencedCode("Evaluates expression-based member chains via reflection; members may be trimmed.")] + internal static IObservable> NotifyForProperty( + object sender, + Expression expression, + bool beforeChange) + { + ArgumentExceptionHelper.ThrowIfNull(expression); + + var memberInfo = expression.GetMemberInfo() ?? throw new ArgumentException( + "The expression does not have valid member info", + nameof(expression)); + var propertyName = memberInfo.Name; + var result = NotifyFactoryCache.Get((sender.GetType(), propertyName, beforeChange)); + + return result switch + { + null => throw new InvalidOperationException( + $"Could not find a ICreatesObservableForProperty for {sender.GetType()} property {propertyName}. {BrokenLocatorAdvice}"), + _ => result.GetNotificationForProperty(sender, expression, propertyName, beforeChange) + }; + } +} diff --git a/src/ReactiveUI.Binding/Observables/ActionDisposable.cs b/src/ReactiveUI.Binding/Observables/ActionDisposable.cs index e1caf44..f3db244 100644 --- a/src/ReactiveUI.Binding/Observables/ActionDisposable.cs +++ b/src/ReactiveUI.Binding/Observables/ActionDisposable.cs @@ -13,14 +13,10 @@ namespace ReactiveUI.Binding.Observables; [EditorBrowsable(EditorBrowsableState.Never)] public sealed class ActionDisposable : IDisposable { - /// - /// The action to invoke on disposal. Set to after first invocation. - /// + /// The action to invoke on disposal. Set to after first invocation. private Action? _action; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The action to invoke on disposal. public ActionDisposable(Action action) { @@ -35,9 +31,7 @@ public void Dispose() action?.Invoke(); } - /// - /// Atomically takes the action, returning it exactly once. Subsequent calls return . - /// + /// Atomically takes the action, returning it exactly once. Subsequent calls return . /// The action if this is the first call; otherwise . [ExcludeFromCodeCoverage] [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ReactiveUI.Binding/Observables/CombineLatest10Observable.cs b/src/ReactiveUI.Binding/Observables/CombineLatest10Observable.cs index 22a079a..0076792 100644 --- a/src/ReactiveUI.Binding/Observables/CombineLatest10Observable.cs +++ b/src/ReactiveUI.Binding/Observables/CombineLatest10Observable.cs @@ -6,9 +6,7 @@ namespace ReactiveUI.Binding.Observables; -/// -/// Lightweight CombineLatest observable that combines the latest values from 10 source observables. -/// +/// Lightweight CombineLatest observable that combines the latest values from 10 source observables. /// The type of element 1. /// The type of element 2. /// The type of element 3. @@ -22,70 +20,42 @@ namespace ReactiveUI.Binding.Observables; /// The result element type. [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] -[SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "Deliberately large arity intrinsic to the N-argument binding/observable API surface.")] internal sealed class CombineLatest10Observable : IObservable { - /// - /// The 1st source observable sequence. - /// + /// The 1st source observable sequence. private readonly IObservable _source1; - /// - /// The 2nd source observable sequence. - /// + /// The 2nd source observable sequence. private readonly IObservable _source2; - /// - /// The 3rd source observable sequence. - /// + /// The 3rd source observable sequence. private readonly IObservable _source3; - /// - /// The 4th source observable sequence. - /// + /// The 4th source observable sequence. private readonly IObservable _source4; - /// - /// The 5th source observable sequence. - /// + /// The 5th source observable sequence. private readonly IObservable _source5; - /// - /// The 6th source observable sequence. - /// + /// The 6th source observable sequence. private readonly IObservable _source6; - /// - /// The 7th source observable sequence. - /// + /// The 7th source observable sequence. private readonly IObservable _source7; - /// - /// The 8th source observable sequence. - /// + /// The 8th source observable sequence. private readonly IObservable _source8; - /// - /// The 9th source observable sequence. - /// + /// The 9th source observable sequence. private readonly IObservable _source9; - /// - /// The 10th source observable sequence. - /// + /// The 10th source observable sequence. private readonly IObservable _source10; - /// - /// The function to combine the latest values from all sources into a result. - /// + /// The function to combine the latest values from all sources into a result. private readonly Func _resultSelector; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The 1st source observable. /// The 2nd source observable. /// The 3rd source observable. @@ -97,6 +67,7 @@ internal sealed class CombineLatest10ObservableThe 9th source observable. /// The 10th source observable. /// The function to combine the latest values. + [SuppressMessage("Design", "SST1472:Signatures should not declare too many parameters", Justification = "Parameter count is intrinsic to the fixed CombineLatest arity.")] public CombineLatest10Observable( IObservable source1, IObservable source2, @@ -153,137 +124,80 @@ public IDisposable Subscribe(IObserver observer) return sub; } - /// - /// Manages the active subscriptions to all ten source observables and emits combined results. - /// - private sealed class Subscription : IDisposable + /// Manages the active subscriptions to all ten source observables and emits combined results. + /// The downstream observer. + /// The function to combine the latest values. + private sealed class Subscription( + IObserver observer, + Func resultSelector) : IDisposable { - /// - /// The subscription array index for source 3. - /// + /// The subscription array index for source 3. private const int Source3Index = 2; - /// - /// The subscription array index for source 4. - /// + /// The subscription array index for source 4. private const int Source4Index = 3; - /// - /// The subscription array index for source 5. - /// + /// The subscription array index for source 5. private const int Source5Index = 4; - /// - /// The subscription array index for source 6. - /// + /// The subscription array index for source 6. private const int Source6Index = 5; - /// - /// The subscription array index for source 7. - /// + /// The subscription array index for source 7. private const int Source7Index = 6; - /// - /// The subscription array index for source 8. - /// + /// The subscription array index for source 8. private const int Source8Index = 7; - /// - /// The subscription array index for source 9. - /// + /// The subscription array index for source 9. private const int Source9Index = 8; - /// - /// The subscription array index for source 10. - /// + /// The subscription array index for source 10. private const int Source10Index = 9; - /// - /// The function to combine the latest values from all sources into a result. - /// - private readonly Func _resultSelector; + /// The function to combine the latest values from all sources into a result. + private readonly Func _resultSelector = resultSelector; - /// - /// The array of inner source subscriptions. - /// + /// The array of inner source subscriptions. private readonly IDisposable?[] _subscriptions = new IDisposable?[10]; - /// - /// The downstream observer receiving combined results. Set to on disposal. - /// - private IObserver? _observer; + /// The downstream observer receiving combined results. Set to on disposal. + private IObserver? _observer = observer; - /// - /// The latest value received from source 1. - /// + /// The latest value received from source 1. private T1 _value1 = default!; - /// - /// The latest value received from source 2. - /// + /// The latest value received from source 2. private T2 _value2 = default!; - /// - /// The latest value received from source 3. - /// + /// The latest value received from source 3. private T3 _value3 = default!; - /// - /// The latest value received from source 4. - /// + /// The latest value received from source 4. private T4 _value4 = default!; - /// - /// The latest value received from source 5. - /// + /// The latest value received from source 5. private T5 _value5 = default!; - /// - /// The latest value received from source 6. - /// + /// The latest value received from source 6. private T6 _value6 = default!; - /// - /// The latest value received from source 7. - /// + /// The latest value received from source 7. private T7 _value7 = default!; - /// - /// The latest value received from source 8. - /// + /// The latest value received from source 8. private T8 _value8 = default!; - /// - /// The latest value received from source 9. - /// + /// The latest value received from source 9. private T9 _value9 = default!; - /// - /// The latest value received from source 10. - /// + /// The latest value received from source 10. private T10 _value10 = default!; - /// - /// Bitmask of the sources that have emitted at least one value; compared against the all-ready mask. - /// + /// Bitmask of the sources that have emitted at least one value; compared against the all-ready mask. private int _readyMask; - /// - /// Initializes a new instance of the class. - /// - /// The downstream observer. - /// The function to combine the latest values. - public Subscription( - IObserver observer, - Func resultSelector) - { - _observer = observer; - _resultSelector = resultSelector; - } - - /// - /// Subscribes to the 1st source observable. - /// + /// Subscribes to the 1st source observable. /// The 1st source observable. public void Subscribe1(IObservable source) { @@ -291,9 +205,7 @@ public void Subscribe1(IObservable source) Volatile.Write(ref _subscriptions[0], sub); } - /// - /// Subscribes to the 2nd source observable. - /// + /// Subscribes to the 2nd source observable. /// The 2nd source observable. public void Subscribe2(IObservable source) { @@ -301,9 +213,7 @@ public void Subscribe2(IObservable source) Volatile.Write(ref _subscriptions[1], sub); } - /// - /// Subscribes to the 3rd source observable. - /// + /// Subscribes to the 3rd source observable. /// The 3rd source observable. public void Subscribe3(IObservable source) { @@ -311,9 +221,7 @@ public void Subscribe3(IObservable source) Volatile.Write(ref _subscriptions[Source3Index], sub); } - /// - /// Subscribes to the 4th source observable. - /// + /// Subscribes to the 4th source observable. /// The 4th source observable. public void Subscribe4(IObservable source) { @@ -321,9 +229,7 @@ public void Subscribe4(IObservable source) Volatile.Write(ref _subscriptions[Source4Index], sub); } - /// - /// Subscribes to the 5th source observable. - /// + /// Subscribes to the 5th source observable. /// The 5th source observable. public void Subscribe5(IObservable source) { @@ -331,9 +237,7 @@ public void Subscribe5(IObservable source) Volatile.Write(ref _subscriptions[Source5Index], sub); } - /// - /// Subscribes to the 6th source observable. - /// + /// Subscribes to the 6th source observable. /// The 6th source observable. public void Subscribe6(IObservable source) { @@ -341,9 +245,7 @@ public void Subscribe6(IObservable source) Volatile.Write(ref _subscriptions[Source6Index], sub); } - /// - /// Subscribes to the 7th source observable. - /// + /// Subscribes to the 7th source observable. /// The 7th source observable. public void Subscribe7(IObservable source) { @@ -351,9 +253,7 @@ public void Subscribe7(IObservable source) Volatile.Write(ref _subscriptions[Source7Index], sub); } - /// - /// Subscribes to the 8th source observable. - /// + /// Subscribes to the 8th source observable. /// The 8th source observable. public void Subscribe8(IObservable source) { @@ -361,9 +261,7 @@ public void Subscribe8(IObservable source) Volatile.Write(ref _subscriptions[Source8Index], sub); } - /// - /// Subscribes to the 9th source observable. - /// + /// Subscribes to the 9th source observable. /// The 9th source observable. public void Subscribe9(IObservable source) { @@ -371,9 +269,7 @@ public void Subscribe9(IObservable source) Volatile.Write(ref _subscriptions[Source9Index], sub); } - /// - /// Subscribes to the 10th source observable. - /// + /// Subscribes to the 10th source observable. /// The 10th source observable. public void Subscribe10(IObservable source) { @@ -384,7 +280,7 @@ public void Subscribe10(IObservable source) /// public void Dispose() { - if (Interlocked.Exchange(ref _observer, null) == null) + if (Interlocked.Exchange(ref _observer, null) is null) { return; } @@ -395,9 +291,7 @@ public void Dispose() } } - /// - /// Emits the combined result if all sources have produced at least one value. - /// + /// Emits the combined result if all sources have produced at least one value. private void TryEmit() { if (_readyMask != (1 << _subscriptions.Length) - 1) @@ -405,12 +299,10 @@ private void TryEmit() return; } - _observer?.OnNext(_resultSelector(_value1, _value2, _value3, _value4, _value5, _value6, _value7, _value8, _value9, _value10)); + Volatile.Read(ref _observer)?.OnNext(_resultSelector(_value1, _value2, _value3, _value4, _value5, _value6, _value7, _value8, _value9, _value10)); } - /// - /// Observer for the 1st source observable. - /// + /// Observer for the 1st source observable. /// The parent subscription. private sealed class Observer1(Subscription parent) : IObserver { @@ -431,9 +323,7 @@ public void OnCompleted() } } - /// - /// Observer for the 2nd source observable. - /// + /// Observer for the 2nd source observable. /// The parent subscription. private sealed class Observer2(Subscription parent) : IObserver { @@ -454,9 +344,7 @@ public void OnCompleted() } } - /// - /// Observer for the 3rd source observable. - /// + /// Observer for the 3rd source observable. /// The parent subscription. private sealed class Observer3(Subscription parent) : IObserver { @@ -477,9 +365,7 @@ public void OnCompleted() } } - /// - /// Observer for the 4th source observable. - /// + /// Observer for the 4th source observable. /// The parent subscription. private sealed class Observer4(Subscription parent) : IObserver { @@ -500,9 +386,7 @@ public void OnCompleted() } } - /// - /// Observer for the 5th source observable. - /// + /// Observer for the 5th source observable. /// The parent subscription. private sealed class Observer5(Subscription parent) : IObserver { @@ -523,9 +407,7 @@ public void OnCompleted() } } - /// - /// Observer for the 6th source observable. - /// + /// Observer for the 6th source observable. /// The parent subscription. private sealed class Observer6(Subscription parent) : IObserver { @@ -546,9 +428,7 @@ public void OnCompleted() } } - /// - /// Observer for the 7th source observable. - /// + /// Observer for the 7th source observable. /// The parent subscription. private sealed class Observer7(Subscription parent) : IObserver { @@ -569,9 +449,7 @@ public void OnCompleted() } } - /// - /// Observer for the 8th source observable. - /// + /// Observer for the 8th source observable. /// The parent subscription. private sealed class Observer8(Subscription parent) : IObserver { @@ -592,9 +470,7 @@ public void OnCompleted() } } - /// - /// Observer for the 9th source observable. - /// + /// Observer for the 9th source observable. /// The parent subscription. private sealed class Observer9(Subscription parent) : IObserver { @@ -615,9 +491,7 @@ public void OnCompleted() } } - /// - /// Observer for the 10th source observable. - /// + /// Observer for the 10th source observable. /// The parent subscription. private sealed class Observer10(Subscription parent) : IObserver { diff --git a/src/ReactiveUI.Binding/Observables/CombineLatest11Observable.cs b/src/ReactiveUI.Binding/Observables/CombineLatest11Observable.cs index f1098ba..d21d8cb 100644 --- a/src/ReactiveUI.Binding/Observables/CombineLatest11Observable.cs +++ b/src/ReactiveUI.Binding/Observables/CombineLatest11Observable.cs @@ -6,9 +6,7 @@ namespace ReactiveUI.Binding.Observables; -/// -/// Lightweight CombineLatest observable that combines the latest values from 11 source observables. -/// +/// Lightweight CombineLatest observable that combines the latest values from 11 source observables. /// The type of element 1. /// The type of element 2. /// The type of element 3. @@ -23,76 +21,46 @@ namespace ReactiveUI.Binding.Observables; /// The result element type. [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] -[SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "Deliberately large arity intrinsic to the N-argument binding/observable API surface.")] internal sealed class CombineLatest11Observable : IObservable { - /// - /// The 1st source observable sequence. - /// + /// The 1st source observable sequence. private readonly IObservable _source1; - /// - /// The 2nd source observable sequence. - /// + /// The 2nd source observable sequence. private readonly IObservable _source2; - /// - /// The 3rd source observable sequence. - /// + /// The 3rd source observable sequence. private readonly IObservable _source3; - /// - /// The 4th source observable sequence. - /// + /// The 4th source observable sequence. private readonly IObservable _source4; - /// - /// The 5th source observable sequence. - /// + /// The 5th source observable sequence. private readonly IObservable _source5; - /// - /// The 6th source observable sequence. - /// + /// The 6th source observable sequence. private readonly IObservable _source6; - /// - /// The 7th source observable sequence. - /// + /// The 7th source observable sequence. private readonly IObservable _source7; - /// - /// The 8th source observable sequence. - /// + /// The 8th source observable sequence. private readonly IObservable _source8; - /// - /// The 9th source observable sequence. - /// + /// The 9th source observable sequence. private readonly IObservable _source9; - /// - /// The 10th source observable sequence. - /// + /// The 10th source observable sequence. private readonly IObservable _source10; - /// - /// The 11th source observable sequence. - /// + /// The 11th source observable sequence. private readonly IObservable _source11; - /// - /// The function to combine the latest values from all sources into a result. - /// + /// The function to combine the latest values from all sources into a result. private readonly Func _resultSelector; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The 1st source observable. /// The 2nd source observable. /// The 3rd source observable. @@ -105,6 +73,7 @@ internal sealed class /// The 10th source observable. /// The 11th source observable. /// The function to combine the latest values. + [SuppressMessage("Design", "SST1472:Signatures should not declare too many parameters", Justification = "Parameter count is intrinsic to the fixed CombineLatest arity.")] public CombineLatest11Observable( IObservable source1, IObservable source2, @@ -165,147 +134,86 @@ public IDisposable Subscribe(IObserver observer) return sub; } - /// - /// Manages the active subscriptions to all eleven source observables and emits combined results. - /// - private sealed class Subscription : IDisposable + /// Manages the active subscriptions to all eleven source observables and emits combined results. + /// The downstream observer. + /// The function to combine the latest values. + private sealed class Subscription( + IObserver observer, + Func resultSelector) : IDisposable { - /// - /// The subscription array index for source 3. - /// + /// The subscription array index for source 3. private const int Source3Index = 2; - /// - /// The subscription array index for source 4. - /// + /// The subscription array index for source 4. private const int Source4Index = 3; - /// - /// The subscription array index for source 5. - /// + /// The subscription array index for source 5. private const int Source5Index = 4; - /// - /// The subscription array index for source 6. - /// + /// The subscription array index for source 6. private const int Source6Index = 5; - /// - /// The subscription array index for source 7. - /// + /// The subscription array index for source 7. private const int Source7Index = 6; - /// - /// The subscription array index for source 8. - /// + /// The subscription array index for source 8. private const int Source8Index = 7; - /// - /// The subscription array index for source 9. - /// + /// The subscription array index for source 9. private const int Source9Index = 8; - /// - /// The subscription array index for source 10. - /// + /// The subscription array index for source 10. private const int Source10Index = 9; - /// - /// The subscription array index for source 11. - /// + /// The subscription array index for source 11. private const int Source11Index = 10; - /// - /// The function to combine the latest values from all sources into a result. - /// - private readonly Func _resultSelector; + /// The function to combine the latest values from all sources into a result. + private readonly Func _resultSelector = resultSelector; - /// - /// The array of inner source subscriptions. - /// + /// The array of inner source subscriptions. private readonly IDisposable?[] _subscriptions = new IDisposable?[11]; - /// - /// The downstream observer receiving combined results. Set to on disposal. - /// - private IObserver? _observer; + /// The downstream observer receiving combined results. Set to on disposal. + private IObserver? _observer = observer; - /// - /// The latest value received from source 1. - /// + /// The latest value received from source 1. private T1 _value1 = default!; - /// - /// The latest value received from source 2. - /// + /// The latest value received from source 2. private T2 _value2 = default!; - /// - /// The latest value received from source 3. - /// + /// The latest value received from source 3. private T3 _value3 = default!; - /// - /// The latest value received from source 4. - /// + /// The latest value received from source 4. private T4 _value4 = default!; - /// - /// The latest value received from source 5. - /// + /// The latest value received from source 5. private T5 _value5 = default!; - /// - /// The latest value received from source 6. - /// + /// The latest value received from source 6. private T6 _value6 = default!; - /// - /// The latest value received from source 7. - /// + /// The latest value received from source 7. private T7 _value7 = default!; - /// - /// The latest value received from source 8. - /// + /// The latest value received from source 8. private T8 _value8 = default!; - /// - /// The latest value received from source 9. - /// + /// The latest value received from source 9. private T9 _value9 = default!; - /// - /// The latest value received from source 10. - /// + /// The latest value received from source 10. private T10 _value10 = default!; - /// - /// The latest value received from source 11. - /// + /// The latest value received from source 11. private T11 _value11 = default!; - /// - /// Bitmask of the sources that have emitted at least one value; compared against the all-ready mask. - /// + /// Bitmask of the sources that have emitted at least one value; compared against the all-ready mask. private int _readyMask; - /// - /// Initializes a new instance of the class. - /// - /// The downstream observer. - /// The function to combine the latest values. - public Subscription( - IObserver observer, - Func resultSelector) - { - _observer = observer; - _resultSelector = resultSelector; - } - - /// - /// Subscribes to the 1st source observable. - /// + /// Subscribes to the 1st source observable. /// The 1st source observable. public void Subscribe1(IObservable source) { @@ -313,9 +221,7 @@ public void Subscribe1(IObservable source) Volatile.Write(ref _subscriptions[0], sub); } - /// - /// Subscribes to the 2nd source observable. - /// + /// Subscribes to the 2nd source observable. /// The 2nd source observable. public void Subscribe2(IObservable source) { @@ -323,9 +229,7 @@ public void Subscribe2(IObservable source) Volatile.Write(ref _subscriptions[1], sub); } - /// - /// Subscribes to the 3rd source observable. - /// + /// Subscribes to the 3rd source observable. /// The 3rd source observable. public void Subscribe3(IObservable source) { @@ -333,9 +237,7 @@ public void Subscribe3(IObservable source) Volatile.Write(ref _subscriptions[Source3Index], sub); } - /// - /// Subscribes to the 4th source observable. - /// + /// Subscribes to the 4th source observable. /// The 4th source observable. public void Subscribe4(IObservable source) { @@ -343,9 +245,7 @@ public void Subscribe4(IObservable source) Volatile.Write(ref _subscriptions[Source4Index], sub); } - /// - /// Subscribes to the 5th source observable. - /// + /// Subscribes to the 5th source observable. /// The 5th source observable. public void Subscribe5(IObservable source) { @@ -353,9 +253,7 @@ public void Subscribe5(IObservable source) Volatile.Write(ref _subscriptions[Source5Index], sub); } - /// - /// Subscribes to the 6th source observable. - /// + /// Subscribes to the 6th source observable. /// The 6th source observable. public void Subscribe6(IObservable source) { @@ -363,9 +261,7 @@ public void Subscribe6(IObservable source) Volatile.Write(ref _subscriptions[Source6Index], sub); } - /// - /// Subscribes to the 7th source observable. - /// + /// Subscribes to the 7th source observable. /// The 7th source observable. public void Subscribe7(IObservable source) { @@ -373,9 +269,7 @@ public void Subscribe7(IObservable source) Volatile.Write(ref _subscriptions[Source7Index], sub); } - /// - /// Subscribes to the 8th source observable. - /// + /// Subscribes to the 8th source observable. /// The 8th source observable. public void Subscribe8(IObservable source) { @@ -383,9 +277,7 @@ public void Subscribe8(IObservable source) Volatile.Write(ref _subscriptions[Source8Index], sub); } - /// - /// Subscribes to the 9th source observable. - /// + /// Subscribes to the 9th source observable. /// The 9th source observable. public void Subscribe9(IObservable source) { @@ -393,9 +285,7 @@ public void Subscribe9(IObservable source) Volatile.Write(ref _subscriptions[Source9Index], sub); } - /// - /// Subscribes to the 10th source observable. - /// + /// Subscribes to the 10th source observable. /// The 10th source observable. public void Subscribe10(IObservable source) { @@ -403,9 +293,7 @@ public void Subscribe10(IObservable source) Volatile.Write(ref _subscriptions[Source10Index], sub); } - /// - /// Subscribes to the 11th source observable. - /// + /// Subscribes to the 11th source observable. /// The 11th source observable. public void Subscribe11(IObservable source) { @@ -416,7 +304,7 @@ public void Subscribe11(IObservable source) /// public void Dispose() { - if (Interlocked.Exchange(ref _observer, null) == null) + if (Interlocked.Exchange(ref _observer, null) is null) { return; } @@ -427,9 +315,7 @@ public void Dispose() } } - /// - /// Emits the combined result if all sources have produced at least one value. - /// + /// Emits the combined result if all sources have produced at least one value. private void TryEmit() { if (_readyMask != (1 << _subscriptions.Length) - 1) @@ -437,12 +323,10 @@ private void TryEmit() return; } - _observer?.OnNext(_resultSelector(_value1, _value2, _value3, _value4, _value5, _value6, _value7, _value8, _value9, _value10, _value11)); + Volatile.Read(ref _observer)?.OnNext(_resultSelector(_value1, _value2, _value3, _value4, _value5, _value6, _value7, _value8, _value9, _value10, _value11)); } - /// - /// Observer for the 1st source observable. - /// + /// Observer for the 1st source observable. /// The parent subscription. private sealed class Observer1(Subscription parent) : IObserver { @@ -463,9 +347,7 @@ public void OnCompleted() } } - /// - /// Observer for the 2nd source observable. - /// + /// Observer for the 2nd source observable. /// The parent subscription. private sealed class Observer2(Subscription parent) : IObserver { @@ -486,9 +368,7 @@ public void OnCompleted() } } - /// - /// Observer for the 3rd source observable. - /// + /// Observer for the 3rd source observable. /// The parent subscription. private sealed class Observer3(Subscription parent) : IObserver { @@ -509,9 +389,7 @@ public void OnCompleted() } } - /// - /// Observer for the 4th source observable. - /// + /// Observer for the 4th source observable. /// The parent subscription. private sealed class Observer4(Subscription parent) : IObserver { @@ -532,9 +410,7 @@ public void OnCompleted() } } - /// - /// Observer for the 5th source observable. - /// + /// Observer for the 5th source observable. /// The parent subscription. private sealed class Observer5(Subscription parent) : IObserver { @@ -555,9 +431,7 @@ public void OnCompleted() } } - /// - /// Observer for the 6th source observable. - /// + /// Observer for the 6th source observable. /// The parent subscription. private sealed class Observer6(Subscription parent) : IObserver { @@ -578,9 +452,7 @@ public void OnCompleted() } } - /// - /// Observer for the 7th source observable. - /// + /// Observer for the 7th source observable. /// The parent subscription. private sealed class Observer7(Subscription parent) : IObserver { @@ -601,9 +473,7 @@ public void OnCompleted() } } - /// - /// Observer for the 8th source observable. - /// + /// Observer for the 8th source observable. /// The parent subscription. private sealed class Observer8(Subscription parent) : IObserver { @@ -624,9 +494,7 @@ public void OnCompleted() } } - /// - /// Observer for the 9th source observable. - /// + /// Observer for the 9th source observable. /// The parent subscription. private sealed class Observer9(Subscription parent) : IObserver { @@ -647,9 +515,7 @@ public void OnCompleted() } } - /// - /// Observer for the 10th source observable. - /// + /// Observer for the 10th source observable. /// The parent subscription. private sealed class Observer10(Subscription parent) : IObserver { @@ -670,9 +536,7 @@ public void OnCompleted() } } - /// - /// Observer for the 11th source observable. - /// + /// Observer for the 11th source observable. /// The parent subscription. private sealed class Observer11(Subscription parent) : IObserver { diff --git a/src/ReactiveUI.Binding/Observables/CombineLatest12Observable.cs b/src/ReactiveUI.Binding/Observables/CombineLatest12Observable.cs index a04e870..618145b 100644 --- a/src/ReactiveUI.Binding/Observables/CombineLatest12Observable.cs +++ b/src/ReactiveUI.Binding/Observables/CombineLatest12Observable.cs @@ -6,9 +6,7 @@ namespace ReactiveUI.Binding.Observables; -/// -/// Lightweight CombineLatest observable that combines the latest values from 12 source observables. -/// +/// Lightweight CombineLatest observable that combines the latest values from 12 source observables. /// The type of element 1. /// The type of element 2. /// The type of element 3. @@ -24,81 +22,49 @@ namespace ReactiveUI.Binding.Observables; /// The result element type. [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] -[SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "Deliberately large arity intrinsic to the N-argument binding/observable API surface.")] internal sealed class CombineLatest12Observable : IObservable { - /// - /// The 1st source observable sequence. - /// + /// The 1st source observable sequence. private readonly IObservable _source1; - /// - /// The 2nd source observable sequence. - /// + /// The 2nd source observable sequence. private readonly IObservable _source2; - /// - /// The 3rd source observable sequence. - /// + /// The 3rd source observable sequence. private readonly IObservable _source3; - /// - /// The 4th source observable sequence. - /// + /// The 4th source observable sequence. private readonly IObservable _source4; - /// - /// The 5th source observable sequence. - /// + /// The 5th source observable sequence. private readonly IObservable _source5; - /// - /// The 6th source observable sequence. - /// + /// The 6th source observable sequence. private readonly IObservable _source6; - /// - /// The 7th source observable sequence. - /// + /// The 7th source observable sequence. private readonly IObservable _source7; - /// - /// The 8th source observable sequence. - /// + /// The 8th source observable sequence. private readonly IObservable _source8; - /// - /// The 9th source observable sequence. - /// + /// The 9th source observable sequence. private readonly IObservable _source9; - /// - /// The 10th source observable sequence. - /// + /// The 10th source observable sequence. private readonly IObservable _source10; - /// - /// The 11th source observable sequence. - /// + /// The 11th source observable sequence. private readonly IObservable _source11; - /// - /// The 12th source observable sequence. - /// + /// The 12th source observable sequence. private readonly IObservable _source12; - /// - /// The function to combine the latest values from all sources into a result. - /// + /// The function to combine the latest values from all sources into a result. private readonly Func _resultSelector; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The 1st source observable. /// The 2nd source observable. /// The 3rd source observable. @@ -112,6 +78,7 @@ internal sealed class /// The 11th source observable. /// The 12th source observable. /// The function to combine the latest values. + [SuppressMessage("Design", "SST1472:Signatures should not declare too many parameters", Justification = "Parameter count is intrinsic to the fixed CombineLatest arity.")] public CombineLatest12Observable( IObservable source1, IObservable source2, @@ -176,157 +143,92 @@ public IDisposable Subscribe(IObserver observer) return sub; } - /// - /// Manages the active subscriptions to all twelve source observables and emits combined results. - /// - private sealed class Subscription : IDisposable + /// Manages the active subscriptions to all twelve source observables and emits combined results. + /// The downstream observer. + /// The function to combine the latest values. + private sealed class Subscription( + IObserver observer, + Func resultSelector) : IDisposable { - /// - /// The subscription array index for source 3. - /// + /// The subscription array index for source 3. private const int Source3Index = 2; - /// - /// The subscription array index for source 4. - /// + /// The subscription array index for source 4. private const int Source4Index = 3; - /// - /// The subscription array index for source 5. - /// + /// The subscription array index for source 5. private const int Source5Index = 4; - /// - /// The subscription array index for source 6. - /// + /// The subscription array index for source 6. private const int Source6Index = 5; - /// - /// The subscription array index for source 7. - /// + /// The subscription array index for source 7. private const int Source7Index = 6; - /// - /// The subscription array index for source 8. - /// + /// The subscription array index for source 8. private const int Source8Index = 7; - /// - /// The subscription array index for source 9. - /// + /// The subscription array index for source 9. private const int Source9Index = 8; - /// - /// The subscription array index for source 10. - /// + /// The subscription array index for source 10. private const int Source10Index = 9; - /// - /// The subscription array index for source 11. - /// + /// The subscription array index for source 11. private const int Source11Index = 10; - /// - /// The subscription array index for source 12. - /// + /// The subscription array index for source 12. private const int Source12Index = 11; - /// - /// The function to combine the latest values from all sources into a result. - /// - private readonly Func _resultSelector; + /// The function to combine the latest values from all sources into a result. + private readonly Func _resultSelector = resultSelector; - /// - /// The array of inner source subscriptions. - /// + /// The array of inner source subscriptions. private readonly IDisposable?[] _subscriptions = new IDisposable?[12]; - /// - /// The downstream observer receiving combined results. Set to on disposal. - /// - private IObserver? _observer; + /// The downstream observer receiving combined results. Set to on disposal. + private IObserver? _observer = observer; - /// - /// The latest value received from source 1. - /// + /// The latest value received from source 1. private T1 _value1 = default!; - /// - /// The latest value received from source 2. - /// + /// The latest value received from source 2. private T2 _value2 = default!; - /// - /// The latest value received from source 3. - /// + /// The latest value received from source 3. private T3 _value3 = default!; - /// - /// The latest value received from source 4. - /// + /// The latest value received from source 4. private T4 _value4 = default!; - /// - /// The latest value received from source 5. - /// + /// The latest value received from source 5. private T5 _value5 = default!; - /// - /// The latest value received from source 6. - /// + /// The latest value received from source 6. private T6 _value6 = default!; - /// - /// The latest value received from source 7. - /// + /// The latest value received from source 7. private T7 _value7 = default!; - /// - /// The latest value received from source 8. - /// + /// The latest value received from source 8. private T8 _value8 = default!; - /// - /// The latest value received from source 9. - /// + /// The latest value received from source 9. private T9 _value9 = default!; - /// - /// The latest value received from source 10. - /// + /// The latest value received from source 10. private T10 _value10 = default!; - /// - /// The latest value received from source 11. - /// + /// The latest value received from source 11. private T11 _value11 = default!; - /// - /// The latest value received from source 12. - /// + /// The latest value received from source 12. private T12 _value12 = default!; - /// - /// Bitmask of the sources that have emitted at least one value; compared against the all-ready mask. - /// + /// Bitmask of the sources that have emitted at least one value; compared against the all-ready mask. private int _readyMask; - /// - /// Initializes a new instance of the class. - /// - /// The downstream observer. - /// The function to combine the latest values. - public Subscription( - IObserver observer, - Func resultSelector) - { - _observer = observer; - _resultSelector = resultSelector; - } - - /// - /// Subscribes to the 1st source observable. - /// + /// Subscribes to the 1st source observable. /// The 1st source observable. public void Subscribe1(IObservable source) { @@ -334,9 +236,7 @@ public void Subscribe1(IObservable source) Volatile.Write(ref _subscriptions[0], sub); } - /// - /// Subscribes to the 2nd source observable. - /// + /// Subscribes to the 2nd source observable. /// The 2nd source observable. public void Subscribe2(IObservable source) { @@ -344,9 +244,7 @@ public void Subscribe2(IObservable source) Volatile.Write(ref _subscriptions[1], sub); } - /// - /// Subscribes to the 3rd source observable. - /// + /// Subscribes to the 3rd source observable. /// The 3rd source observable. public void Subscribe3(IObservable source) { @@ -354,9 +252,7 @@ public void Subscribe3(IObservable source) Volatile.Write(ref _subscriptions[Source3Index], sub); } - /// - /// Subscribes to the 4th source observable. - /// + /// Subscribes to the 4th source observable. /// The 4th source observable. public void Subscribe4(IObservable source) { @@ -364,9 +260,7 @@ public void Subscribe4(IObservable source) Volatile.Write(ref _subscriptions[Source4Index], sub); } - /// - /// Subscribes to the 5th source observable. - /// + /// Subscribes to the 5th source observable. /// The 5th source observable. public void Subscribe5(IObservable source) { @@ -374,9 +268,7 @@ public void Subscribe5(IObservable source) Volatile.Write(ref _subscriptions[Source5Index], sub); } - /// - /// Subscribes to the 6th source observable. - /// + /// Subscribes to the 6th source observable. /// The 6th source observable. public void Subscribe6(IObservable source) { @@ -384,9 +276,7 @@ public void Subscribe6(IObservable source) Volatile.Write(ref _subscriptions[Source6Index], sub); } - /// - /// Subscribes to the 7th source observable. - /// + /// Subscribes to the 7th source observable. /// The 7th source observable. public void Subscribe7(IObservable source) { @@ -394,9 +284,7 @@ public void Subscribe7(IObservable source) Volatile.Write(ref _subscriptions[Source7Index], sub); } - /// - /// Subscribes to the 8th source observable. - /// + /// Subscribes to the 8th source observable. /// The 8th source observable. public void Subscribe8(IObservable source) { @@ -404,9 +292,7 @@ public void Subscribe8(IObservable source) Volatile.Write(ref _subscriptions[Source8Index], sub); } - /// - /// Subscribes to the 9th source observable. - /// + /// Subscribes to the 9th source observable. /// The 9th source observable. public void Subscribe9(IObservable source) { @@ -414,9 +300,7 @@ public void Subscribe9(IObservable source) Volatile.Write(ref _subscriptions[Source9Index], sub); } - /// - /// Subscribes to the 10th source observable. - /// + /// Subscribes to the 10th source observable. /// The 10th source observable. public void Subscribe10(IObservable source) { @@ -424,9 +308,7 @@ public void Subscribe10(IObservable source) Volatile.Write(ref _subscriptions[Source10Index], sub); } - /// - /// Subscribes to the 11th source observable. - /// + /// Subscribes to the 11th source observable. /// The 11th source observable. public void Subscribe11(IObservable source) { @@ -434,9 +316,7 @@ public void Subscribe11(IObservable source) Volatile.Write(ref _subscriptions[Source11Index], sub); } - /// - /// Subscribes to the 12th source observable. - /// + /// Subscribes to the 12th source observable. /// The 12th source observable. public void Subscribe12(IObservable source) { @@ -447,7 +327,7 @@ public void Subscribe12(IObservable source) /// public void Dispose() { - if (Interlocked.Exchange(ref _observer, null) == null) + if (Interlocked.Exchange(ref _observer, null) is null) { return; } @@ -458,9 +338,7 @@ public void Dispose() } } - /// - /// Emits the combined result if all sources have produced at least one value. - /// + /// Emits the combined result if all sources have produced at least one value. private void TryEmit() { if (_readyMask != (1 << _subscriptions.Length) - 1) @@ -468,12 +346,10 @@ private void TryEmit() return; } - _observer?.OnNext(_resultSelector(_value1, _value2, _value3, _value4, _value5, _value6, _value7, _value8, _value9, _value10, _value11, _value12)); + Volatile.Read(ref _observer)?.OnNext(_resultSelector(_value1, _value2, _value3, _value4, _value5, _value6, _value7, _value8, _value9, _value10, _value11, _value12)); } - /// - /// Observer for the 1st source observable. - /// + /// Observer for the 1st source observable. /// The parent subscription. private sealed class Observer1(Subscription parent) : IObserver { @@ -494,9 +370,7 @@ public void OnCompleted() } } - /// - /// Observer for the 2nd source observable. - /// + /// Observer for the 2nd source observable. /// The parent subscription. private sealed class Observer2(Subscription parent) : IObserver { @@ -517,9 +391,7 @@ public void OnCompleted() } } - /// - /// Observer for the 3rd source observable. - /// + /// Observer for the 3rd source observable. /// The parent subscription. private sealed class Observer3(Subscription parent) : IObserver { @@ -540,9 +412,7 @@ public void OnCompleted() } } - /// - /// Observer for the 4th source observable. - /// + /// Observer for the 4th source observable. /// The parent subscription. private sealed class Observer4(Subscription parent) : IObserver { @@ -563,9 +433,7 @@ public void OnCompleted() } } - /// - /// Observer for the 5th source observable. - /// + /// Observer for the 5th source observable. /// The parent subscription. private sealed class Observer5(Subscription parent) : IObserver { @@ -586,9 +454,7 @@ public void OnCompleted() } } - /// - /// Observer for the 6th source observable. - /// + /// Observer for the 6th source observable. /// The parent subscription. private sealed class Observer6(Subscription parent) : IObserver { @@ -609,9 +475,7 @@ public void OnCompleted() } } - /// - /// Observer for the 7th source observable. - /// + /// Observer for the 7th source observable. /// The parent subscription. private sealed class Observer7(Subscription parent) : IObserver { @@ -632,9 +496,7 @@ public void OnCompleted() } } - /// - /// Observer for the 8th source observable. - /// + /// Observer for the 8th source observable. /// The parent subscription. private sealed class Observer8(Subscription parent) : IObserver { @@ -655,9 +517,7 @@ public void OnCompleted() } } - /// - /// Observer for the 9th source observable. - /// + /// Observer for the 9th source observable. /// The parent subscription. private sealed class Observer9(Subscription parent) : IObserver { @@ -678,9 +538,7 @@ public void OnCompleted() } } - /// - /// Observer for the 10th source observable. - /// + /// Observer for the 10th source observable. /// The parent subscription. private sealed class Observer10(Subscription parent) : IObserver { @@ -701,9 +559,7 @@ public void OnCompleted() } } - /// - /// Observer for the 11th source observable. - /// + /// Observer for the 11th source observable. /// The parent subscription. private sealed class Observer11(Subscription parent) : IObserver { @@ -724,9 +580,7 @@ public void OnCompleted() } } - /// - /// Observer for the 12th source observable. - /// + /// Observer for the 12th source observable. /// The parent subscription. private sealed class Observer12(Subscription parent) : IObserver { diff --git a/src/ReactiveUI.Binding/Observables/CombineLatest13Observable.cs b/src/ReactiveUI.Binding/Observables/CombineLatest13Observable.cs index a603ce1..7e57a24 100644 --- a/src/ReactiveUI.Binding/Observables/CombineLatest13Observable.cs +++ b/src/ReactiveUI.Binding/Observables/CombineLatest13Observable.cs @@ -6,9 +6,7 @@ namespace ReactiveUI.Binding.Observables; -/// -/// Lightweight CombineLatest observable that combines the latest values from 13 source observables. -/// +/// Lightweight CombineLatest observable that combines the latest values from 13 source observables. /// The type of element 1. /// The type of element 2. /// The type of element 3. @@ -25,86 +23,52 @@ namespace ReactiveUI.Binding.Observables; /// The result element type. [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] -[SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "Deliberately large arity intrinsic to the N-argument binding/observable API surface.")] internal sealed class CombineLatest13Observable : IObservable { - /// - /// The 1st source observable sequence. - /// + /// The 1st source observable sequence. private readonly IObservable _source1; - /// - /// The 2nd source observable sequence. - /// + /// The 2nd source observable sequence. private readonly IObservable _source2; - /// - /// The 3rd source observable sequence. - /// + /// The 3rd source observable sequence. private readonly IObservable _source3; - /// - /// The 4th source observable sequence. - /// + /// The 4th source observable sequence. private readonly IObservable _source4; - /// - /// The 5th source observable sequence. - /// + /// The 5th source observable sequence. private readonly IObservable _source5; - /// - /// The 6th source observable sequence. - /// + /// The 6th source observable sequence. private readonly IObservable _source6; - /// - /// The 7th source observable sequence. - /// + /// The 7th source observable sequence. private readonly IObservable _source7; - /// - /// The 8th source observable sequence. - /// + /// The 8th source observable sequence. private readonly IObservable _source8; - /// - /// The 9th source observable sequence. - /// + /// The 9th source observable sequence. private readonly IObservable _source9; - /// - /// The 10th source observable sequence. - /// + /// The 10th source observable sequence. private readonly IObservable _source10; - /// - /// The 11th source observable sequence. - /// + /// The 11th source observable sequence. private readonly IObservable _source11; - /// - /// The 12th source observable sequence. - /// + /// The 12th source observable sequence. private readonly IObservable _source12; - /// - /// The 13th source observable sequence. - /// + /// The 13th source observable sequence. private readonly IObservable _source13; - /// - /// The function to combine the latest values from all sources into a result. - /// + /// The function to combine the latest values from all sources into a result. private readonly Func _resultSelector; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The 1st source observable. /// The 2nd source observable. /// The 3rd source observable. @@ -119,6 +83,7 @@ internal sealed class /// The 12th source observable. /// The 13th source observable. /// The function to combine the latest values. + [SuppressMessage("Design", "SST1472:Signatures should not declare too many parameters", Justification = "Parameter count is intrinsic to the fixed CombineLatest arity.")] public CombineLatest13Observable( IObservable source1, IObservable source2, @@ -187,167 +152,98 @@ public IDisposable Subscribe(IObserver observer) return sub; } - /// - /// Manages the active subscriptions to all thirteen source observables and emits combined results. - /// - private sealed class Subscription : IDisposable + /// Manages the active subscriptions to all thirteen source observables and emits combined results. + /// The downstream observer. + /// The function to combine the latest values. + private sealed class Subscription( + IObserver observer, + Func resultSelector) : IDisposable { - /// - /// The subscription array index for source 3. - /// + /// The subscription array index for source 3. private const int Source3Index = 2; - /// - /// The subscription array index for source 4. - /// + /// The subscription array index for source 4. private const int Source4Index = 3; - /// - /// The subscription array index for source 5. - /// + /// The subscription array index for source 5. private const int Source5Index = 4; - /// - /// The subscription array index for source 6. - /// + /// The subscription array index for source 6. private const int Source6Index = 5; - /// - /// The subscription array index for source 7. - /// + /// The subscription array index for source 7. private const int Source7Index = 6; - /// - /// The subscription array index for source 8. - /// + /// The subscription array index for source 8. private const int Source8Index = 7; - /// - /// The subscription array index for source 9. - /// + /// The subscription array index for source 9. private const int Source9Index = 8; - /// - /// The subscription array index for source 10. - /// + /// The subscription array index for source 10. private const int Source10Index = 9; - /// - /// The subscription array index for source 11. - /// + /// The subscription array index for source 11. private const int Source11Index = 10; - /// - /// The subscription array index for source 12. - /// + /// The subscription array index for source 12. private const int Source12Index = 11; - /// - /// The subscription array index for source 13. - /// + /// The subscription array index for source 13. private const int Source13Index = 12; - /// - /// The function to combine the latest values from all sources into a result. - /// - private readonly Func _resultSelector; + /// The function to combine the latest values from all sources into a result. + private readonly Func _resultSelector = resultSelector; - /// - /// The array of inner source subscriptions. - /// + /// The array of inner source subscriptions. private readonly IDisposable?[] _subscriptions = new IDisposable?[13]; - /// - /// The downstream observer receiving combined results. Set to on disposal. - /// - private IObserver? _observer; + /// The downstream observer receiving combined results. Set to on disposal. + private IObserver? _observer = observer; - /// - /// The latest value received from source 1. - /// + /// The latest value received from source 1. private T1 _value1 = default!; - /// - /// The latest value received from source 2. - /// + /// The latest value received from source 2. private T2 _value2 = default!; - /// - /// The latest value received from source 3. - /// + /// The latest value received from source 3. private T3 _value3 = default!; - /// - /// The latest value received from source 4. - /// + /// The latest value received from source 4. private T4 _value4 = default!; - /// - /// The latest value received from source 5. - /// + /// The latest value received from source 5. private T5 _value5 = default!; - /// - /// The latest value received from source 6. - /// + /// The latest value received from source 6. private T6 _value6 = default!; - /// - /// The latest value received from source 7. - /// + /// The latest value received from source 7. private T7 _value7 = default!; - /// - /// The latest value received from source 8. - /// + /// The latest value received from source 8. private T8 _value8 = default!; - /// - /// The latest value received from source 9. - /// + /// The latest value received from source 9. private T9 _value9 = default!; - /// - /// The latest value received from source 10. - /// + /// The latest value received from source 10. private T10 _value10 = default!; - /// - /// The latest value received from source 11. - /// + /// The latest value received from source 11. private T11 _value11 = default!; - /// - /// The latest value received from source 12. - /// + /// The latest value received from source 12. private T12 _value12 = default!; - /// - /// The latest value received from source 13. - /// + /// The latest value received from source 13. private T13 _value13 = default!; - /// - /// Bitmask of the sources that have emitted at least one value; compared against the all-ready mask. - /// + /// Bitmask of the sources that have emitted at least one value; compared against the all-ready mask. private int _readyMask; - /// - /// Initializes a new instance of the class. - /// - /// The downstream observer. - /// The function to combine the latest values. - public Subscription( - IObserver observer, - Func resultSelector) - { - _observer = observer; - _resultSelector = resultSelector; - } - - /// - /// Subscribes to the 1st source observable. - /// + /// Subscribes to the 1st source observable. /// The 1st source observable. public void Subscribe1(IObservable source) { @@ -355,9 +251,7 @@ public void Subscribe1(IObservable source) Volatile.Write(ref _subscriptions[0], sub); } - /// - /// Subscribes to the 2nd source observable. - /// + /// Subscribes to the 2nd source observable. /// The 2nd source observable. public void Subscribe2(IObservable source) { @@ -365,9 +259,7 @@ public void Subscribe2(IObservable source) Volatile.Write(ref _subscriptions[1], sub); } - /// - /// Subscribes to the 3rd source observable. - /// + /// Subscribes to the 3rd source observable. /// The 3rd source observable. public void Subscribe3(IObservable source) { @@ -375,9 +267,7 @@ public void Subscribe3(IObservable source) Volatile.Write(ref _subscriptions[Source3Index], sub); } - /// - /// Subscribes to the 4th source observable. - /// + /// Subscribes to the 4th source observable. /// The 4th source observable. public void Subscribe4(IObservable source) { @@ -385,9 +275,7 @@ public void Subscribe4(IObservable source) Volatile.Write(ref _subscriptions[Source4Index], sub); } - /// - /// Subscribes to the 5th source observable. - /// + /// Subscribes to the 5th source observable. /// The 5th source observable. public void Subscribe5(IObservable source) { @@ -395,9 +283,7 @@ public void Subscribe5(IObservable source) Volatile.Write(ref _subscriptions[Source5Index], sub); } - /// - /// Subscribes to the 6th source observable. - /// + /// Subscribes to the 6th source observable. /// The 6th source observable. public void Subscribe6(IObservable source) { @@ -405,9 +291,7 @@ public void Subscribe6(IObservable source) Volatile.Write(ref _subscriptions[Source6Index], sub); } - /// - /// Subscribes to the 7th source observable. - /// + /// Subscribes to the 7th source observable. /// The 7th source observable. public void Subscribe7(IObservable source) { @@ -415,9 +299,7 @@ public void Subscribe7(IObservable source) Volatile.Write(ref _subscriptions[Source7Index], sub); } - /// - /// Subscribes to the 8th source observable. - /// + /// Subscribes to the 8th source observable. /// The 8th source observable. public void Subscribe8(IObservable source) { @@ -425,9 +307,7 @@ public void Subscribe8(IObservable source) Volatile.Write(ref _subscriptions[Source8Index], sub); } - /// - /// Subscribes to the 9th source observable. - /// + /// Subscribes to the 9th source observable. /// The 9th source observable. public void Subscribe9(IObservable source) { @@ -435,9 +315,7 @@ public void Subscribe9(IObservable source) Volatile.Write(ref _subscriptions[Source9Index], sub); } - /// - /// Subscribes to the 10th source observable. - /// + /// Subscribes to the 10th source observable. /// The 10th source observable. public void Subscribe10(IObservable source) { @@ -445,9 +323,7 @@ public void Subscribe10(IObservable source) Volatile.Write(ref _subscriptions[Source10Index], sub); } - /// - /// Subscribes to the 11th source observable. - /// + /// Subscribes to the 11th source observable. /// The 11th source observable. public void Subscribe11(IObservable source) { @@ -455,9 +331,7 @@ public void Subscribe11(IObservable source) Volatile.Write(ref _subscriptions[Source11Index], sub); } - /// - /// Subscribes to the 12th source observable. - /// + /// Subscribes to the 12th source observable. /// The 12th source observable. public void Subscribe12(IObservable source) { @@ -465,9 +339,7 @@ public void Subscribe12(IObservable source) Volatile.Write(ref _subscriptions[Source12Index], sub); } - /// - /// Subscribes to the 13th source observable. - /// + /// Subscribes to the 13th source observable. /// The 13th source observable. public void Subscribe13(IObservable source) { @@ -478,7 +350,7 @@ public void Subscribe13(IObservable source) /// public void Dispose() { - if (Interlocked.Exchange(ref _observer, null) == null) + if (Interlocked.Exchange(ref _observer, null) is null) { return; } @@ -489,9 +361,7 @@ public void Dispose() } } - /// - /// Emits the combined result if all sources have produced at least one value. - /// + /// Emits the combined result if all sources have produced at least one value. private void TryEmit() { if (_readyMask != (1 << _subscriptions.Length) - 1) @@ -499,12 +369,10 @@ private void TryEmit() return; } - _observer?.OnNext(_resultSelector(_value1, _value2, _value3, _value4, _value5, _value6, _value7, _value8, _value9, _value10, _value11, _value12, _value13)); + Volatile.Read(ref _observer)?.OnNext(_resultSelector(_value1, _value2, _value3, _value4, _value5, _value6, _value7, _value8, _value9, _value10, _value11, _value12, _value13)); } - /// - /// Observer for the 1st source observable. - /// + /// Observer for the 1st source observable. /// The parent subscription. private sealed class Observer1(Subscription parent) : IObserver { @@ -525,9 +393,7 @@ public void OnCompleted() } } - /// - /// Observer for the 2nd source observable. - /// + /// Observer for the 2nd source observable. /// The parent subscription. private sealed class Observer2(Subscription parent) : IObserver { @@ -548,9 +414,7 @@ public void OnCompleted() } } - /// - /// Observer for the 3rd source observable. - /// + /// Observer for the 3rd source observable. /// The parent subscription. private sealed class Observer3(Subscription parent) : IObserver { @@ -571,9 +435,7 @@ public void OnCompleted() } } - /// - /// Observer for the 4th source observable. - /// + /// Observer for the 4th source observable. /// The parent subscription. private sealed class Observer4(Subscription parent) : IObserver { @@ -594,9 +456,7 @@ public void OnCompleted() } } - /// - /// Observer for the 5th source observable. - /// + /// Observer for the 5th source observable. /// The parent subscription. private sealed class Observer5(Subscription parent) : IObserver { @@ -617,9 +477,7 @@ public void OnCompleted() } } - /// - /// Observer for the 6th source observable. - /// + /// Observer for the 6th source observable. /// The parent subscription. private sealed class Observer6(Subscription parent) : IObserver { @@ -640,9 +498,7 @@ public void OnCompleted() } } - /// - /// Observer for the 7th source observable. - /// + /// Observer for the 7th source observable. /// The parent subscription. private sealed class Observer7(Subscription parent) : IObserver { @@ -663,9 +519,7 @@ public void OnCompleted() } } - /// - /// Observer for the 8th source observable. - /// + /// Observer for the 8th source observable. /// The parent subscription. private sealed class Observer8(Subscription parent) : IObserver { @@ -686,9 +540,7 @@ public void OnCompleted() } } - /// - /// Observer for the 9th source observable. - /// + /// Observer for the 9th source observable. /// The parent subscription. private sealed class Observer9(Subscription parent) : IObserver { @@ -709,9 +561,7 @@ public void OnCompleted() } } - /// - /// Observer for the 10th source observable. - /// + /// Observer for the 10th source observable. /// The parent subscription. private sealed class Observer10(Subscription parent) : IObserver { @@ -732,9 +582,7 @@ public void OnCompleted() } } - /// - /// Observer for the 11th source observable. - /// + /// Observer for the 11th source observable. /// The parent subscription. private sealed class Observer11(Subscription parent) : IObserver { @@ -755,9 +603,7 @@ public void OnCompleted() } } - /// - /// Observer for the 12th source observable. - /// + /// Observer for the 12th source observable. /// The parent subscription. private sealed class Observer12(Subscription parent) : IObserver { @@ -778,9 +624,7 @@ public void OnCompleted() } } - /// - /// Observer for the 13th source observable. - /// + /// Observer for the 13th source observable. /// The parent subscription. private sealed class Observer13(Subscription parent) : IObserver { diff --git a/src/ReactiveUI.Binding/Observables/CombineLatest14Observable.cs b/src/ReactiveUI.Binding/Observables/CombineLatest14Observable.cs index 7768440..2cc1daf 100644 --- a/src/ReactiveUI.Binding/Observables/CombineLatest14Observable.cs +++ b/src/ReactiveUI.Binding/Observables/CombineLatest14Observable.cs @@ -6,9 +6,7 @@ namespace ReactiveUI.Binding.Observables; -/// -/// Lightweight CombineLatest observable that combines the latest values from 14 source observables. -/// +/// Lightweight CombineLatest observable that combines the latest values from 14 source observables. /// The type of element 1. /// The type of element 2. /// The type of element 3. @@ -26,10 +24,6 @@ namespace ReactiveUI.Binding.Observables; /// The result element type. [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] -[SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "Deliberately large arity intrinsic to the N-argument binding/observable API surface.")] internal sealed class CombineLatest14Observable< T1, @@ -48,84 +42,52 @@ internal sealed class T14, TResult> : IObservable { - /// - /// The 1st source observable sequence. - /// + /// The 1st source observable sequence. private readonly IObservable _source1; - /// - /// The 2nd source observable sequence. - /// + /// The 2nd source observable sequence. private readonly IObservable _source2; - /// - /// The 3rd source observable sequence. - /// + /// The 3rd source observable sequence. private readonly IObservable _source3; - /// - /// The 4th source observable sequence. - /// + /// The 4th source observable sequence. private readonly IObservable _source4; - /// - /// The 5th source observable sequence. - /// + /// The 5th source observable sequence. private readonly IObservable _source5; - /// - /// The 6th source observable sequence. - /// + /// The 6th source observable sequence. private readonly IObservable _source6; - /// - /// The 7th source observable sequence. - /// + /// The 7th source observable sequence. private readonly IObservable _source7; - /// - /// The 8th source observable sequence. - /// + /// The 8th source observable sequence. private readonly IObservable _source8; - /// - /// The 9th source observable sequence. - /// + /// The 9th source observable sequence. private readonly IObservable _source9; - /// - /// The 10th source observable sequence. - /// + /// The 10th source observable sequence. private readonly IObservable _source10; - /// - /// The 11th source observable sequence. - /// + /// The 11th source observable sequence. private readonly IObservable _source11; - /// - /// The 12th source observable sequence. - /// + /// The 12th source observable sequence. private readonly IObservable _source12; - /// - /// The 13th source observable sequence. - /// + /// The 13th source observable sequence. private readonly IObservable _source13; - /// - /// The 14th source observable sequence. - /// + /// The 14th source observable sequence. private readonly IObservable _source14; - /// - /// The function to combine the latest values from all sources into a result. - /// + /// The function to combine the latest values from all sources into a result. private readonly Func _resultSelector; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The 1st source observable. /// The 2nd source observable. /// The 3rd source observable. @@ -141,6 +103,7 @@ internal sealed class /// The 13th source observable. /// The 14th source observable. /// The function to combine the latest values. + [SuppressMessage("Design", "SST1472:Signatures should not declare too many parameters", Justification = "Parameter count is intrinsic to the fixed CombineLatest arity.")] public CombineLatest14Observable( IObservable source1, IObservable source2, @@ -213,177 +176,104 @@ public IDisposable Subscribe(IObserver observer) return sub; } - /// - /// Manages the active subscriptions to all fourteen source observables and emits combined results. - /// - private sealed class Subscription : IDisposable + /// Manages the active subscriptions to all fourteen source observables and emits combined results. + /// The downstream observer. + /// The function to combine the latest values. + private sealed class Subscription( + IObserver observer, + Func resultSelector) : IDisposable { - /// - /// The subscription array index for source 3. - /// + /// The subscription array index for source 3. private const int Source3Index = 2; - /// - /// The subscription array index for source 4. - /// + /// The subscription array index for source 4. private const int Source4Index = 3; - /// - /// The subscription array index for source 5. - /// + /// The subscription array index for source 5. private const int Source5Index = 4; - /// - /// The subscription array index for source 6. - /// + /// The subscription array index for source 6. private const int Source6Index = 5; - /// - /// The subscription array index for source 7. - /// + /// The subscription array index for source 7. private const int Source7Index = 6; - /// - /// The subscription array index for source 8. - /// + /// The subscription array index for source 8. private const int Source8Index = 7; - /// - /// The subscription array index for source 9. - /// + /// The subscription array index for source 9. private const int Source9Index = 8; - /// - /// The subscription array index for source 10. - /// + /// The subscription array index for source 10. private const int Source10Index = 9; - /// - /// The subscription array index for source 11. - /// + /// The subscription array index for source 11. private const int Source11Index = 10; - /// - /// The subscription array index for source 12. - /// + /// The subscription array index for source 12. private const int Source12Index = 11; - /// - /// The subscription array index for source 13. - /// + /// The subscription array index for source 13. private const int Source13Index = 12; - /// - /// The subscription array index for source 14. - /// + /// The subscription array index for source 14. private const int Source14Index = 13; - /// - /// The function to combine the latest values from all sources into a result. - /// - private readonly Func _resultSelector; + /// The function to combine the latest values from all sources into a result. + private readonly Func _resultSelector = resultSelector; - /// - /// The array of inner source subscriptions. - /// + /// The array of inner source subscriptions. private readonly IDisposable?[] _subscriptions = new IDisposable?[14]; - /// - /// The downstream observer receiving combined results. Set to on disposal. - /// - private IObserver? _observer; + /// The downstream observer receiving combined results. Set to on disposal. + private IObserver? _observer = observer; - /// - /// The latest value received from source 1. - /// + /// The latest value received from source 1. private T1 _value1 = default!; - /// - /// The latest value received from source 2. - /// + /// The latest value received from source 2. private T2 _value2 = default!; - /// - /// The latest value received from source 3. - /// + /// The latest value received from source 3. private T3 _value3 = default!; - /// - /// The latest value received from source 4. - /// + /// The latest value received from source 4. private T4 _value4 = default!; - /// - /// The latest value received from source 5. - /// + /// The latest value received from source 5. private T5 _value5 = default!; - /// - /// The latest value received from source 6. - /// + /// The latest value received from source 6. private T6 _value6 = default!; - /// - /// The latest value received from source 7. - /// + /// The latest value received from source 7. private T7 _value7 = default!; - /// - /// The latest value received from source 8. - /// + /// The latest value received from source 8. private T8 _value8 = default!; - /// - /// The latest value received from source 9. - /// + /// The latest value received from source 9. private T9 _value9 = default!; - /// - /// The latest value received from source 10. - /// + /// The latest value received from source 10. private T10 _value10 = default!; - /// - /// The latest value received from source 11. - /// + /// The latest value received from source 11. private T11 _value11 = default!; - /// - /// The latest value received from source 12. - /// + /// The latest value received from source 12. private T12 _value12 = default!; - /// - /// The latest value received from source 13. - /// + /// The latest value received from source 13. private T13 _value13 = default!; - /// - /// The latest value received from source 14. - /// + /// The latest value received from source 14. private T14 _value14 = default!; - /// - /// Bitmask of the sources that have emitted at least one value; compared against the all-ready mask. - /// + /// Bitmask of the sources that have emitted at least one value; compared against the all-ready mask. private int _readyMask; - /// - /// Initializes a new instance of the class. - /// - /// The downstream observer. - /// The function to combine the latest values. - public Subscription( - IObserver observer, - Func resultSelector) - { - _observer = observer; - _resultSelector = resultSelector; - } - - /// - /// Subscribes to the 1st source observable. - /// + /// Subscribes to the 1st source observable. /// The 1st source observable. public void Subscribe1(IObservable source) { @@ -391,9 +281,7 @@ public void Subscribe1(IObservable source) Volatile.Write(ref _subscriptions[0], sub); } - /// - /// Subscribes to the 2nd source observable. - /// + /// Subscribes to the 2nd source observable. /// The 2nd source observable. public void Subscribe2(IObservable source) { @@ -401,9 +289,7 @@ public void Subscribe2(IObservable source) Volatile.Write(ref _subscriptions[1], sub); } - /// - /// Subscribes to the 3rd source observable. - /// + /// Subscribes to the 3rd source observable. /// The 3rd source observable. public void Subscribe3(IObservable source) { @@ -411,9 +297,7 @@ public void Subscribe3(IObservable source) Volatile.Write(ref _subscriptions[Source3Index], sub); } - /// - /// Subscribes to the 4th source observable. - /// + /// Subscribes to the 4th source observable. /// The 4th source observable. public void Subscribe4(IObservable source) { @@ -421,9 +305,7 @@ public void Subscribe4(IObservable source) Volatile.Write(ref _subscriptions[Source4Index], sub); } - /// - /// Subscribes to the 5th source observable. - /// + /// Subscribes to the 5th source observable. /// The 5th source observable. public void Subscribe5(IObservable source) { @@ -431,9 +313,7 @@ public void Subscribe5(IObservable source) Volatile.Write(ref _subscriptions[Source5Index], sub); } - /// - /// Subscribes to the 6th source observable. - /// + /// Subscribes to the 6th source observable. /// The 6th source observable. public void Subscribe6(IObservable source) { @@ -441,9 +321,7 @@ public void Subscribe6(IObservable source) Volatile.Write(ref _subscriptions[Source6Index], sub); } - /// - /// Subscribes to the 7th source observable. - /// + /// Subscribes to the 7th source observable. /// The 7th source observable. public void Subscribe7(IObservable source) { @@ -451,9 +329,7 @@ public void Subscribe7(IObservable source) Volatile.Write(ref _subscriptions[Source7Index], sub); } - /// - /// Subscribes to the 8th source observable. - /// + /// Subscribes to the 8th source observable. /// The 8th source observable. public void Subscribe8(IObservable source) { @@ -461,9 +337,7 @@ public void Subscribe8(IObservable source) Volatile.Write(ref _subscriptions[Source8Index], sub); } - /// - /// Subscribes to the 9th source observable. - /// + /// Subscribes to the 9th source observable. /// The 9th source observable. public void Subscribe9(IObservable source) { @@ -471,9 +345,7 @@ public void Subscribe9(IObservable source) Volatile.Write(ref _subscriptions[Source9Index], sub); } - /// - /// Subscribes to the 10th source observable. - /// + /// Subscribes to the 10th source observable. /// The 10th source observable. public void Subscribe10(IObservable source) { @@ -481,9 +353,7 @@ public void Subscribe10(IObservable source) Volatile.Write(ref _subscriptions[Source10Index], sub); } - /// - /// Subscribes to the 11th source observable. - /// + /// Subscribes to the 11th source observable. /// The 11th source observable. public void Subscribe11(IObservable source) { @@ -491,9 +361,7 @@ public void Subscribe11(IObservable source) Volatile.Write(ref _subscriptions[Source11Index], sub); } - /// - /// Subscribes to the 12th source observable. - /// + /// Subscribes to the 12th source observable. /// The 12th source observable. public void Subscribe12(IObservable source) { @@ -501,9 +369,7 @@ public void Subscribe12(IObservable source) Volatile.Write(ref _subscriptions[Source12Index], sub); } - /// - /// Subscribes to the 13th source observable. - /// + /// Subscribes to the 13th source observable. /// The 13th source observable. public void Subscribe13(IObservable source) { @@ -511,9 +377,7 @@ public void Subscribe13(IObservable source) Volatile.Write(ref _subscriptions[Source13Index], sub); } - /// - /// Subscribes to the 14th source observable. - /// + /// Subscribes to the 14th source observable. /// The 14th source observable. public void Subscribe14(IObservable source) { @@ -524,7 +388,7 @@ public void Subscribe14(IObservable source) /// public void Dispose() { - if (Interlocked.Exchange(ref _observer, null) == null) + if (Interlocked.Exchange(ref _observer, null) is null) { return; } @@ -535,9 +399,7 @@ public void Dispose() } } - /// - /// Emits the combined result if all sources have produced at least one value. - /// + /// Emits the combined result if all sources have produced at least one value. private void TryEmit() { if (_readyMask != (1 << _subscriptions.Length) - 1) @@ -545,12 +407,10 @@ private void TryEmit() return; } - _observer?.OnNext(_resultSelector(_value1, _value2, _value3, _value4, _value5, _value6, _value7, _value8, _value9, _value10, _value11, _value12, _value13, _value14)); + Volatile.Read(ref _observer)?.OnNext(_resultSelector(_value1, _value2, _value3, _value4, _value5, _value6, _value7, _value8, _value9, _value10, _value11, _value12, _value13, _value14)); } - /// - /// Observer for the 1st source observable. - /// + /// Observer for the 1st source observable. /// The parent subscription. private sealed class Observer1(Subscription parent) : IObserver { @@ -571,9 +431,7 @@ public void OnCompleted() } } - /// - /// Observer for the 2nd source observable. - /// + /// Observer for the 2nd source observable. /// The parent subscription. private sealed class Observer2(Subscription parent) : IObserver { @@ -594,9 +452,7 @@ public void OnCompleted() } } - /// - /// Observer for the 3rd source observable. - /// + /// Observer for the 3rd source observable. /// The parent subscription. private sealed class Observer3(Subscription parent) : IObserver { @@ -617,9 +473,7 @@ public void OnCompleted() } } - /// - /// Observer for the 4th source observable. - /// + /// Observer for the 4th source observable. /// The parent subscription. private sealed class Observer4(Subscription parent) : IObserver { @@ -640,9 +494,7 @@ public void OnCompleted() } } - /// - /// Observer for the 5th source observable. - /// + /// Observer for the 5th source observable. /// The parent subscription. private sealed class Observer5(Subscription parent) : IObserver { @@ -663,9 +515,7 @@ public void OnCompleted() } } - /// - /// Observer for the 6th source observable. - /// + /// Observer for the 6th source observable. /// The parent subscription. private sealed class Observer6(Subscription parent) : IObserver { @@ -686,9 +536,7 @@ public void OnCompleted() } } - /// - /// Observer for the 7th source observable. - /// + /// Observer for the 7th source observable. /// The parent subscription. private sealed class Observer7(Subscription parent) : IObserver { @@ -709,9 +557,7 @@ public void OnCompleted() } } - /// - /// Observer for the 8th source observable. - /// + /// Observer for the 8th source observable. /// The parent subscription. private sealed class Observer8(Subscription parent) : IObserver { @@ -732,9 +578,7 @@ public void OnCompleted() } } - /// - /// Observer for the 9th source observable. - /// + /// Observer for the 9th source observable. /// The parent subscription. private sealed class Observer9(Subscription parent) : IObserver { @@ -755,9 +599,7 @@ public void OnCompleted() } } - /// - /// Observer for the 10th source observable. - /// + /// Observer for the 10th source observable. /// The parent subscription. private sealed class Observer10(Subscription parent) : IObserver { @@ -778,9 +620,7 @@ public void OnCompleted() } } - /// - /// Observer for the 11th source observable. - /// + /// Observer for the 11th source observable. /// The parent subscription. private sealed class Observer11(Subscription parent) : IObserver { @@ -801,9 +641,7 @@ public void OnCompleted() } } - /// - /// Observer for the 12th source observable. - /// + /// Observer for the 12th source observable. /// The parent subscription. private sealed class Observer12(Subscription parent) : IObserver { @@ -824,9 +662,7 @@ public void OnCompleted() } } - /// - /// Observer for the 13th source observable. - /// + /// Observer for the 13th source observable. /// The parent subscription. private sealed class Observer13(Subscription parent) : IObserver { @@ -847,9 +683,7 @@ public void OnCompleted() } } - /// - /// Observer for the 14th source observable. - /// + /// Observer for the 14th source observable. /// The parent subscription. private sealed class Observer14(Subscription parent) : IObserver { diff --git a/src/ReactiveUI.Binding/Observables/CombineLatest15Observable.cs b/src/ReactiveUI.Binding/Observables/CombineLatest15Observable.cs index cdce0d1..0559a04 100644 --- a/src/ReactiveUI.Binding/Observables/CombineLatest15Observable.cs +++ b/src/ReactiveUI.Binding/Observables/CombineLatest15Observable.cs @@ -6,9 +6,7 @@ namespace ReactiveUI.Binding.Observables; -/// -/// Lightweight CombineLatest observable that combines the latest values from 15 source observables. -/// +/// Lightweight CombineLatest observable that combines the latest values from 15 source observables. /// The type of element 1. /// The type of element 2. /// The type of element 3. @@ -27,10 +25,6 @@ namespace ReactiveUI.Binding.Observables; /// The result element type. [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] -[SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "Deliberately large arity intrinsic to the N-argument binding/observable API surface.")] internal sealed class CombineLatest15Observable< T1, T2, @@ -49,89 +43,55 @@ internal sealed class CombineLatest15Observable< T15, TResult> : IObservable { - /// - /// The 1st source observable sequence. - /// + /// The 1st source observable sequence. private readonly IObservable _source1; - /// - /// The 2nd source observable sequence. - /// + /// The 2nd source observable sequence. private readonly IObservable _source2; - /// - /// The 3rd source observable sequence. - /// + /// The 3rd source observable sequence. private readonly IObservable _source3; - /// - /// The 4th source observable sequence. - /// + /// The 4th source observable sequence. private readonly IObservable _source4; - /// - /// The 5th source observable sequence. - /// + /// The 5th source observable sequence. private readonly IObservable _source5; - /// - /// The 6th source observable sequence. - /// + /// The 6th source observable sequence. private readonly IObservable _source6; - /// - /// The 7th source observable sequence. - /// + /// The 7th source observable sequence. private readonly IObservable _source7; - /// - /// The 8th source observable sequence. - /// + /// The 8th source observable sequence. private readonly IObservable _source8; - /// - /// The 9th source observable sequence. - /// + /// The 9th source observable sequence. private readonly IObservable _source9; - /// - /// The 10th source observable sequence. - /// + /// The 10th source observable sequence. private readonly IObservable _source10; - /// - /// The 11th source observable sequence. - /// + /// The 11th source observable sequence. private readonly IObservable _source11; - /// - /// The 12th source observable sequence. - /// + /// The 12th source observable sequence. private readonly IObservable _source12; - /// - /// The 13th source observable sequence. - /// + /// The 13th source observable sequence. private readonly IObservable _source13; - /// - /// The 14th source observable sequence. - /// + /// The 14th source observable sequence. private readonly IObservable _source14; - /// - /// The 15th source observable sequence. - /// + /// The 15th source observable sequence. private readonly IObservable _source15; - /// - /// The function to combine the latest values from all sources into a result. - /// + /// The function to combine the latest values from all sources into a result. private readonly Func _resultSelector; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The 1st source observable. /// The 2nd source observable. /// The 3rd source observable. @@ -148,6 +108,7 @@ internal sealed class CombineLatest15Observable< /// The 14th source observable. /// The 15th source observable. /// The function to combine the latest values. + [SuppressMessage("Design", "SST1472:Signatures should not declare too many parameters", Justification = "Parameter count is intrinsic to the fixed CombineLatest arity.")] public CombineLatest15Observable( IObservable source1, IObservable source2, @@ -224,188 +185,111 @@ public IDisposable Subscribe(IObserver observer) return sub; } - /// - /// Manages the active subscriptions to all fifteen source observables and emits combined results. - /// - private sealed class Subscription : IDisposable + /// Manages the active subscriptions to all fifteen source observables and emits combined results. + /// The downstream observer. + /// The function to combine the latest values. + private sealed class Subscription( + IObserver observer, + Func resultSelector) : IDisposable { - /// - /// The subscription array index for source 3. - /// + /// The subscription array index for source 3. private const int Source3Index = 2; - /// - /// The subscription array index for source 4. - /// + /// The subscription array index for source 4. private const int Source4Index = 3; - /// - /// The subscription array index for source 5. - /// + /// The subscription array index for source 5. private const int Source5Index = 4; - /// - /// The subscription array index for source 6. - /// + /// The subscription array index for source 6. private const int Source6Index = 5; - /// - /// The subscription array index for source 7. - /// + /// The subscription array index for source 7. private const int Source7Index = 6; - /// - /// The subscription array index for source 8. - /// + /// The subscription array index for source 8. private const int Source8Index = 7; - /// - /// The subscription array index for source 9. - /// + /// The subscription array index for source 9. private const int Source9Index = 8; - /// - /// The subscription array index for source 10. - /// + /// The subscription array index for source 10. private const int Source10Index = 9; - /// - /// The subscription array index for source 11. - /// + /// The subscription array index for source 11. private const int Source11Index = 10; - /// - /// The subscription array index for source 12. - /// + /// The subscription array index for source 12. private const int Source12Index = 11; - /// - /// The subscription array index for source 13. - /// + /// The subscription array index for source 13. private const int Source13Index = 12; - /// - /// The subscription array index for source 14. - /// + /// The subscription array index for source 14. private const int Source14Index = 13; - /// - /// The subscription array index for source 15. - /// + /// The subscription array index for source 15. private const int Source15Index = 14; - /// - /// The function to combine the latest values from all sources into a result. - /// + /// The function to combine the latest values from all sources into a result. private readonly Func - _resultSelector; + _resultSelector = resultSelector; - /// - /// The array of inner source subscriptions. - /// + /// The array of inner source subscriptions. private readonly IDisposable?[] _subscriptions = new IDisposable?[15]; - /// - /// The downstream observer receiving combined results. Set to on disposal. - /// - private IObserver? _observer; + /// The downstream observer receiving combined results. Set to on disposal. + private IObserver? _observer = observer; - /// - /// The latest value received from source 1. - /// + /// The latest value received from source 1. private T1 _value1 = default!; - /// - /// The latest value received from source 2. - /// + /// The latest value received from source 2. private T2 _value2 = default!; - /// - /// The latest value received from source 3. - /// + /// The latest value received from source 3. private T3 _value3 = default!; - /// - /// The latest value received from source 4. - /// + /// The latest value received from source 4. private T4 _value4 = default!; - /// - /// The latest value received from source 5. - /// + /// The latest value received from source 5. private T5 _value5 = default!; - /// - /// The latest value received from source 6. - /// + /// The latest value received from source 6. private T6 _value6 = default!; - /// - /// The latest value received from source 7. - /// + /// The latest value received from source 7. private T7 _value7 = default!; - /// - /// The latest value received from source 8. - /// + /// The latest value received from source 8. private T8 _value8 = default!; - /// - /// The latest value received from source 9. - /// + /// The latest value received from source 9. private T9 _value9 = default!; - /// - /// The latest value received from source 10. - /// + /// The latest value received from source 10. private T10 _value10 = default!; - /// - /// The latest value received from source 11. - /// + /// The latest value received from source 11. private T11 _value11 = default!; - /// - /// The latest value received from source 12. - /// + /// The latest value received from source 12. private T12 _value12 = default!; - /// - /// The latest value received from source 13. - /// + /// The latest value received from source 13. private T13 _value13 = default!; - /// - /// The latest value received from source 14. - /// + /// The latest value received from source 14. private T14 _value14 = default!; - /// - /// The latest value received from source 15. - /// + /// The latest value received from source 15. private T15 _value15 = default!; - /// - /// Bitmask of the sources that have emitted at least one value; compared against the all-ready mask. - /// + /// Bitmask of the sources that have emitted at least one value; compared against the all-ready mask. private int _readyMask; - /// - /// Initializes a new instance of the class. - /// - /// The downstream observer. - /// The function to combine the latest values. - public Subscription( - IObserver observer, - Func resultSelector) - { - _observer = observer; - _resultSelector = resultSelector; - } - - /// - /// Subscribes to the 1st source observable. - /// + /// Subscribes to the 1st source observable. /// The 1st source observable. public void Subscribe1(IObservable source) { @@ -413,9 +297,7 @@ public void Subscribe1(IObservable source) Volatile.Write(ref _subscriptions[0], sub); } - /// - /// Subscribes to the 2nd source observable. - /// + /// Subscribes to the 2nd source observable. /// The 2nd source observable. public void Subscribe2(IObservable source) { @@ -423,9 +305,7 @@ public void Subscribe2(IObservable source) Volatile.Write(ref _subscriptions[1], sub); } - /// - /// Subscribes to the 3rd source observable. - /// + /// Subscribes to the 3rd source observable. /// The 3rd source observable. public void Subscribe3(IObservable source) { @@ -433,9 +313,7 @@ public void Subscribe3(IObservable source) Volatile.Write(ref _subscriptions[Source3Index], sub); } - /// - /// Subscribes to the 4th source observable. - /// + /// Subscribes to the 4th source observable. /// The 4th source observable. public void Subscribe4(IObservable source) { @@ -443,9 +321,7 @@ public void Subscribe4(IObservable source) Volatile.Write(ref _subscriptions[Source4Index], sub); } - /// - /// Subscribes to the 5th source observable. - /// + /// Subscribes to the 5th source observable. /// The 5th source observable. public void Subscribe5(IObservable source) { @@ -453,9 +329,7 @@ public void Subscribe5(IObservable source) Volatile.Write(ref _subscriptions[Source5Index], sub); } - /// - /// Subscribes to the 6th source observable. - /// + /// Subscribes to the 6th source observable. /// The 6th source observable. public void Subscribe6(IObservable source) { @@ -463,9 +337,7 @@ public void Subscribe6(IObservable source) Volatile.Write(ref _subscriptions[Source6Index], sub); } - /// - /// Subscribes to the 7th source observable. - /// + /// Subscribes to the 7th source observable. /// The 7th source observable. public void Subscribe7(IObservable source) { @@ -473,9 +345,7 @@ public void Subscribe7(IObservable source) Volatile.Write(ref _subscriptions[Source7Index], sub); } - /// - /// Subscribes to the 8th source observable. - /// + /// Subscribes to the 8th source observable. /// The 8th source observable. public void Subscribe8(IObservable source) { @@ -483,9 +353,7 @@ public void Subscribe8(IObservable source) Volatile.Write(ref _subscriptions[Source8Index], sub); } - /// - /// Subscribes to the 9th source observable. - /// + /// Subscribes to the 9th source observable. /// The 9th source observable. public void Subscribe9(IObservable source) { @@ -493,9 +361,7 @@ public void Subscribe9(IObservable source) Volatile.Write(ref _subscriptions[Source9Index], sub); } - /// - /// Subscribes to the 10th source observable. - /// + /// Subscribes to the 10th source observable. /// The 10th source observable. public void Subscribe10(IObservable source) { @@ -503,9 +369,7 @@ public void Subscribe10(IObservable source) Volatile.Write(ref _subscriptions[Source10Index], sub); } - /// - /// Subscribes to the 11th source observable. - /// + /// Subscribes to the 11th source observable. /// The 11th source observable. public void Subscribe11(IObservable source) { @@ -513,9 +377,7 @@ public void Subscribe11(IObservable source) Volatile.Write(ref _subscriptions[Source11Index], sub); } - /// - /// Subscribes to the 12th source observable. - /// + /// Subscribes to the 12th source observable. /// The 12th source observable. public void Subscribe12(IObservable source) { @@ -523,9 +385,7 @@ public void Subscribe12(IObservable source) Volatile.Write(ref _subscriptions[Source12Index], sub); } - /// - /// Subscribes to the 13th source observable. - /// + /// Subscribes to the 13th source observable. /// The 13th source observable. public void Subscribe13(IObservable source) { @@ -533,9 +393,7 @@ public void Subscribe13(IObservable source) Volatile.Write(ref _subscriptions[Source13Index], sub); } - /// - /// Subscribes to the 14th source observable. - /// + /// Subscribes to the 14th source observable. /// The 14th source observable. public void Subscribe14(IObservable source) { @@ -543,9 +401,7 @@ public void Subscribe14(IObservable source) Volatile.Write(ref _subscriptions[Source14Index], sub); } - /// - /// Subscribes to the 15th source observable. - /// + /// Subscribes to the 15th source observable. /// The 15th source observable. public void Subscribe15(IObservable source) { @@ -556,7 +412,7 @@ public void Subscribe15(IObservable source) /// public void Dispose() { - if (Interlocked.Exchange(ref _observer, null) == null) + if (Interlocked.Exchange(ref _observer, null) is null) { return; } @@ -567,9 +423,7 @@ public void Dispose() } } - /// - /// Emits the combined result if all sources have produced at least one value. - /// + /// Emits the combined result if all sources have produced at least one value. private void TryEmit() { if (_readyMask != (1 << _subscriptions.Length) - 1) @@ -577,12 +431,25 @@ private void TryEmit() return; } - _observer?.OnNext(_resultSelector(_value1, _value2, _value3, _value4, _value5, _value6, _value7, _value8, _value9, _value10, _value11, _value12, _value13, _value14, _value15)); - } - - /// - /// Observer for the 1st source observable. - /// + Volatile.Read(ref _observer)?.OnNext(_resultSelector( + _value1, + _value2, + _value3, + _value4, + _value5, + _value6, + _value7, + _value8, + _value9, + _value10, + _value11, + _value12, + _value13, + _value14, + _value15)); + } + + /// Observer for the 1st source observable. /// The parent subscription. private sealed class Observer1(Subscription parent) : IObserver { @@ -603,9 +470,7 @@ public void OnCompleted() } } - /// - /// Observer for the 2nd source observable. - /// + /// Observer for the 2nd source observable. /// The parent subscription. private sealed class Observer2(Subscription parent) : IObserver { @@ -626,9 +491,7 @@ public void OnCompleted() } } - /// - /// Observer for the 3rd source observable. - /// + /// Observer for the 3rd source observable. /// The parent subscription. private sealed class Observer3(Subscription parent) : IObserver { @@ -649,9 +512,7 @@ public void OnCompleted() } } - /// - /// Observer for the 4th source observable. - /// + /// Observer for the 4th source observable. /// The parent subscription. private sealed class Observer4(Subscription parent) : IObserver { @@ -672,9 +533,7 @@ public void OnCompleted() } } - /// - /// Observer for the 5th source observable. - /// + /// Observer for the 5th source observable. /// The parent subscription. private sealed class Observer5(Subscription parent) : IObserver { @@ -695,9 +554,7 @@ public void OnCompleted() } } - /// - /// Observer for the 6th source observable. - /// + /// Observer for the 6th source observable. /// The parent subscription. private sealed class Observer6(Subscription parent) : IObserver { @@ -718,9 +575,7 @@ public void OnCompleted() } } - /// - /// Observer for the 7th source observable. - /// + /// Observer for the 7th source observable. /// The parent subscription. private sealed class Observer7(Subscription parent) : IObserver { @@ -741,9 +596,7 @@ public void OnCompleted() } } - /// - /// Observer for the 8th source observable. - /// + /// Observer for the 8th source observable. /// The parent subscription. private sealed class Observer8(Subscription parent) : IObserver { @@ -764,9 +617,7 @@ public void OnCompleted() } } - /// - /// Observer for the 9th source observable. - /// + /// Observer for the 9th source observable. /// The parent subscription. private sealed class Observer9(Subscription parent) : IObserver { @@ -787,9 +638,7 @@ public void OnCompleted() } } - /// - /// Observer for the 10th source observable. - /// + /// Observer for the 10th source observable. /// The parent subscription. private sealed class Observer10(Subscription parent) : IObserver { @@ -810,9 +659,7 @@ public void OnCompleted() } } - /// - /// Observer for the 11th source observable. - /// + /// Observer for the 11th source observable. /// The parent subscription. private sealed class Observer11(Subscription parent) : IObserver { @@ -833,9 +680,7 @@ public void OnCompleted() } } - /// - /// Observer for the 12th source observable. - /// + /// Observer for the 12th source observable. /// The parent subscription. private sealed class Observer12(Subscription parent) : IObserver { @@ -856,9 +701,7 @@ public void OnCompleted() } } - /// - /// Observer for the 13th source observable. - /// + /// Observer for the 13th source observable. /// The parent subscription. private sealed class Observer13(Subscription parent) : IObserver { @@ -879,9 +722,7 @@ public void OnCompleted() } } - /// - /// Observer for the 14th source observable. - /// + /// Observer for the 14th source observable. /// The parent subscription. private sealed class Observer14(Subscription parent) : IObserver { @@ -902,9 +743,7 @@ public void OnCompleted() } } - /// - /// Observer for the 15th source observable. - /// + /// Observer for the 15th source observable. /// The parent subscription. private sealed class Observer15(Subscription parent) : IObserver { diff --git a/src/ReactiveUI.Binding/Observables/CombineLatest16Observable.cs b/src/ReactiveUI.Binding/Observables/CombineLatest16Observable.cs index 1fbc88d..d7bcacb 100644 --- a/src/ReactiveUI.Binding/Observables/CombineLatest16Observable.cs +++ b/src/ReactiveUI.Binding/Observables/CombineLatest16Observable.cs @@ -6,9 +6,7 @@ namespace ReactiveUI.Binding.Observables; -/// -/// Lightweight CombineLatest observable that combines the latest values from 16 source observables. -/// +/// Lightweight CombineLatest observable that combines the latest values from 16 source observables. /// The type of element 1. /// The type of element 2. /// The type of element 3. @@ -28,10 +26,6 @@ namespace ReactiveUI.Binding.Observables; /// The result element type. [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] -[SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "Deliberately large arity intrinsic to the N-argument binding/observable API surface.")] internal sealed class CombineLatest16Observable< T1, T2, @@ -51,95 +45,59 @@ internal sealed class CombineLatest16Observable< T16, TResult> : IObservable { - /// - /// The 1st source observable sequence. - /// + /// The 1st source observable sequence. private readonly IObservable _source1; - /// - /// The 2nd source observable sequence. - /// + /// The 2nd source observable sequence. private readonly IObservable _source2; - /// - /// The 3rd source observable sequence. - /// + /// The 3rd source observable sequence. private readonly IObservable _source3; - /// - /// The 4th source observable sequence. - /// + /// The 4th source observable sequence. private readonly IObservable _source4; - /// - /// The 5th source observable sequence. - /// + /// The 5th source observable sequence. private readonly IObservable _source5; - /// - /// The 6th source observable sequence. - /// + /// The 6th source observable sequence. private readonly IObservable _source6; - /// - /// The 7th source observable sequence. - /// + /// The 7th source observable sequence. private readonly IObservable _source7; - /// - /// The 8th source observable sequence. - /// + /// The 8th source observable sequence. private readonly IObservable _source8; - /// - /// The 9th source observable sequence. - /// + /// The 9th source observable sequence. private readonly IObservable _source9; - /// - /// The 10th source observable sequence. - /// + /// The 10th source observable sequence. private readonly IObservable _source10; - /// - /// The 11th source observable sequence. - /// + /// The 11th source observable sequence. private readonly IObservable _source11; - /// - /// The 12th source observable sequence. - /// + /// The 12th source observable sequence. private readonly IObservable _source12; - /// - /// The 13th source observable sequence. - /// + /// The 13th source observable sequence. private readonly IObservable _source13; - /// - /// The 14th source observable sequence. - /// + /// The 14th source observable sequence. private readonly IObservable _source14; - /// - /// The 15th source observable sequence. - /// + /// The 15th source observable sequence. private readonly IObservable _source15; - /// - /// The 16th source observable sequence. - /// + /// The 16th source observable sequence. private readonly IObservable _source16; - /// - /// The function to combine the latest values from all sources into a result. - /// + /// The function to combine the latest values from all sources into a result. private readonly Func _resultSelector; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The 1st source observable. /// The 2nd source observable. /// The 3rd source observable. @@ -157,6 +115,7 @@ private readonly FuncThe 15th source observable. /// The 16th source observable. /// The function to combine the latest values. + [SuppressMessage("Design", "SST1472:Signatures should not declare too many parameters", Justification = "Parameter count is intrinsic to the fixed CombineLatest arity.")] public CombineLatest16Observable( IObservable source1, IObservable source2, @@ -237,198 +196,117 @@ public IDisposable Subscribe(IObserver observer) return sub; } - /// - /// Manages the active subscriptions to all sixteen source observables and emits combined results. - /// - private sealed class Subscription : IDisposable + /// Manages the active subscriptions to all sixteen source observables and emits combined results. + /// The downstream observer. + /// The function to combine the latest values. + private sealed class Subscription( + IObserver observer, + Func resultSelector) : IDisposable { - /// - /// The subscription array index for source 3. - /// + /// The subscription array index for source 3. private const int Source3Index = 2; - /// - /// The subscription array index for source 4. - /// + /// The subscription array index for source 4. private const int Source4Index = 3; - /// - /// The subscription array index for source 5. - /// + /// The subscription array index for source 5. private const int Source5Index = 4; - /// - /// The subscription array index for source 6. - /// + /// The subscription array index for source 6. private const int Source6Index = 5; - /// - /// The subscription array index for source 7. - /// + /// The subscription array index for source 7. private const int Source7Index = 6; - /// - /// The subscription array index for source 8. - /// + /// The subscription array index for source 8. private const int Source8Index = 7; - /// - /// The subscription array index for source 9. - /// + /// The subscription array index for source 9. private const int Source9Index = 8; - /// - /// The subscription array index for source 10. - /// + /// The subscription array index for source 10. private const int Source10Index = 9; - /// - /// The subscription array index for source 11. - /// + /// The subscription array index for source 11. private const int Source11Index = 10; - /// - /// The subscription array index for source 12. - /// + /// The subscription array index for source 12. private const int Source12Index = 11; - /// - /// The subscription array index for source 13. - /// + /// The subscription array index for source 13. private const int Source13Index = 12; - /// - /// The subscription array index for source 14. - /// + /// The subscription array index for source 14. private const int Source14Index = 13; - /// - /// The subscription array index for source 15. - /// + /// The subscription array index for source 15. private const int Source15Index = 14; - /// - /// The subscription array index for source 16. - /// + /// The subscription array index for source 16. private const int Source16Index = 15; - /// - /// The function to combine the latest values from all sources into a result. - /// + /// The function to combine the latest values from all sources into a result. private readonly Func - _resultSelector; + _resultSelector = resultSelector; - /// - /// The array of inner source subscriptions. - /// + /// The array of inner source subscriptions. private readonly IDisposable?[] _subscriptions = new IDisposable?[16]; - /// - /// The downstream observer receiving combined results. Set to on disposal. - /// - private IObserver? _observer; + /// The downstream observer receiving combined results. Set to on disposal. + private IObserver? _observer = observer; - /// - /// The latest value received from source 1. - /// + /// The latest value received from source 1. private T1 _value1 = default!; - /// - /// The latest value received from source 2. - /// + /// The latest value received from source 2. private T2 _value2 = default!; - /// - /// The latest value received from source 3. - /// + /// The latest value received from source 3. private T3 _value3 = default!; - /// - /// The latest value received from source 4. - /// + /// The latest value received from source 4. private T4 _value4 = default!; - /// - /// The latest value received from source 5. - /// + /// The latest value received from source 5. private T5 _value5 = default!; - /// - /// The latest value received from source 6. - /// + /// The latest value received from source 6. private T6 _value6 = default!; - /// - /// The latest value received from source 7. - /// + /// The latest value received from source 7. private T7 _value7 = default!; - /// - /// The latest value received from source 8. - /// + /// The latest value received from source 8. private T8 _value8 = default!; - /// - /// The latest value received from source 9. - /// + /// The latest value received from source 9. private T9 _value9 = default!; - /// - /// The latest value received from source 10. - /// + /// The latest value received from source 10. private T10 _value10 = default!; - /// - /// The latest value received from source 11. - /// + /// The latest value received from source 11. private T11 _value11 = default!; - /// - /// The latest value received from source 12. - /// + /// The latest value received from source 12. private T12 _value12 = default!; - /// - /// The latest value received from source 13. - /// + /// The latest value received from source 13. private T13 _value13 = default!; - /// - /// The latest value received from source 14. - /// + /// The latest value received from source 14. private T14 _value14 = default!; - /// - /// The latest value received from source 15. - /// + /// The latest value received from source 15. private T15 _value15 = default!; - /// - /// The latest value received from source 16. - /// + /// The latest value received from source 16. private T16 _value16 = default!; - /// - /// Bitmask of the sources that have emitted at least one value; compared against the all-ready mask. - /// + /// Bitmask of the sources that have emitted at least one value; compared against the all-ready mask. private int _readyMask; - /// - /// Initializes a new instance of the class. - /// - /// The downstream observer. - /// The function to combine the latest values. - public Subscription( - IObserver observer, - Func resultSelector) - { - _observer = observer; - _resultSelector = resultSelector; - } - - /// - /// Subscribes to the 1st source observable. - /// + /// Subscribes to the 1st source observable. /// The 1st source observable. public void Subscribe1(IObservable source) { @@ -436,9 +314,7 @@ public void Subscribe1(IObservable source) Volatile.Write(ref _subscriptions[0], sub); } - /// - /// Subscribes to the 2nd source observable. - /// + /// Subscribes to the 2nd source observable. /// The 2nd source observable. public void Subscribe2(IObservable source) { @@ -446,9 +322,7 @@ public void Subscribe2(IObservable source) Volatile.Write(ref _subscriptions[1], sub); } - /// - /// Subscribes to the 3rd source observable. - /// + /// Subscribes to the 3rd source observable. /// The 3rd source observable. public void Subscribe3(IObservable source) { @@ -456,9 +330,7 @@ public void Subscribe3(IObservable source) Volatile.Write(ref _subscriptions[Source3Index], sub); } - /// - /// Subscribes to the 4th source observable. - /// + /// Subscribes to the 4th source observable. /// The 4th source observable. public void Subscribe4(IObservable source) { @@ -466,9 +338,7 @@ public void Subscribe4(IObservable source) Volatile.Write(ref _subscriptions[Source4Index], sub); } - /// - /// Subscribes to the 5th source observable. - /// + /// Subscribes to the 5th source observable. /// The 5th source observable. public void Subscribe5(IObservable source) { @@ -476,9 +346,7 @@ public void Subscribe5(IObservable source) Volatile.Write(ref _subscriptions[Source5Index], sub); } - /// - /// Subscribes to the 6th source observable. - /// + /// Subscribes to the 6th source observable. /// The 6th source observable. public void Subscribe6(IObservable source) { @@ -486,9 +354,7 @@ public void Subscribe6(IObservable source) Volatile.Write(ref _subscriptions[Source6Index], sub); } - /// - /// Subscribes to the 7th source observable. - /// + /// Subscribes to the 7th source observable. /// The 7th source observable. public void Subscribe7(IObservable source) { @@ -496,9 +362,7 @@ public void Subscribe7(IObservable source) Volatile.Write(ref _subscriptions[Source7Index], sub); } - /// - /// Subscribes to the 8th source observable. - /// + /// Subscribes to the 8th source observable. /// The 8th source observable. public void Subscribe8(IObservable source) { @@ -506,9 +370,7 @@ public void Subscribe8(IObservable source) Volatile.Write(ref _subscriptions[Source8Index], sub); } - /// - /// Subscribes to the 9th source observable. - /// + /// Subscribes to the 9th source observable. /// The 9th source observable. public void Subscribe9(IObservable source) { @@ -516,9 +378,7 @@ public void Subscribe9(IObservable source) Volatile.Write(ref _subscriptions[Source9Index], sub); } - /// - /// Subscribes to the 10th source observable. - /// + /// Subscribes to the 10th source observable. /// The 10th source observable. public void Subscribe10(IObservable source) { @@ -526,9 +386,7 @@ public void Subscribe10(IObservable source) Volatile.Write(ref _subscriptions[Source10Index], sub); } - /// - /// Subscribes to the 11th source observable. - /// + /// Subscribes to the 11th source observable. /// The 11th source observable. public void Subscribe11(IObservable source) { @@ -536,9 +394,7 @@ public void Subscribe11(IObservable source) Volatile.Write(ref _subscriptions[Source11Index], sub); } - /// - /// Subscribes to the 12th source observable. - /// + /// Subscribes to the 12th source observable. /// The 12th source observable. public void Subscribe12(IObservable source) { @@ -546,9 +402,7 @@ public void Subscribe12(IObservable source) Volatile.Write(ref _subscriptions[Source12Index], sub); } - /// - /// Subscribes to the 13th source observable. - /// + /// Subscribes to the 13th source observable. /// The 13th source observable. public void Subscribe13(IObservable source) { @@ -556,9 +410,7 @@ public void Subscribe13(IObservable source) Volatile.Write(ref _subscriptions[Source13Index], sub); } - /// - /// Subscribes to the 14th source observable. - /// + /// Subscribes to the 14th source observable. /// The 14th source observable. public void Subscribe14(IObservable source) { @@ -566,9 +418,7 @@ public void Subscribe14(IObservable source) Volatile.Write(ref _subscriptions[Source14Index], sub); } - /// - /// Subscribes to the 15th source observable. - /// + /// Subscribes to the 15th source observable. /// The 15th source observable. public void Subscribe15(IObservable source) { @@ -576,9 +426,7 @@ public void Subscribe15(IObservable source) Volatile.Write(ref _subscriptions[Source15Index], sub); } - /// - /// Subscribes to the 16th source observable. - /// + /// Subscribes to the 16th source observable. /// The 16th source observable. public void Subscribe16(IObservable source) { @@ -589,7 +437,7 @@ public void Subscribe16(IObservable source) /// public void Dispose() { - if (Interlocked.Exchange(ref _observer, null) == null) + if (Interlocked.Exchange(ref _observer, null) is null) { return; } @@ -600,9 +448,7 @@ public void Dispose() } } - /// - /// Emits the combined result if all sources have produced at least one value. - /// + /// Emits the combined result if all sources have produced at least one value. private void TryEmit() { if (_readyMask != (1 << _subscriptions.Length) - 1) @@ -610,12 +456,26 @@ private void TryEmit() return; } - _observer?.OnNext(_resultSelector(_value1, _value2, _value3, _value4, _value5, _value6, _value7, _value8, _value9, _value10, _value11, _value12, _value13, _value14, _value15, _value16)); - } - - /// - /// Observer for the 1st source observable. - /// + Volatile.Read(ref _observer)?.OnNext(_resultSelector( + _value1, + _value2, + _value3, + _value4, + _value5, + _value6, + _value7, + _value8, + _value9, + _value10, + _value11, + _value12, + _value13, + _value14, + _value15, + _value16)); + } + + /// Observer for the 1st source observable. /// The parent subscription. private sealed class Observer1(Subscription parent) : IObserver { @@ -636,9 +496,7 @@ public void OnCompleted() } } - /// - /// Observer for the 2nd source observable. - /// + /// Observer for the 2nd source observable. /// The parent subscription. private sealed class Observer2(Subscription parent) : IObserver { @@ -659,9 +517,7 @@ public void OnCompleted() } } - /// - /// Observer for the 3rd source observable. - /// + /// Observer for the 3rd source observable. /// The parent subscription. private sealed class Observer3(Subscription parent) : IObserver { @@ -682,9 +538,7 @@ public void OnCompleted() } } - /// - /// Observer for the 4th source observable. - /// + /// Observer for the 4th source observable. /// The parent subscription. private sealed class Observer4(Subscription parent) : IObserver { @@ -705,9 +559,7 @@ public void OnCompleted() } } - /// - /// Observer for the 5th source observable. - /// + /// Observer for the 5th source observable. /// The parent subscription. private sealed class Observer5(Subscription parent) : IObserver { @@ -728,9 +580,7 @@ public void OnCompleted() } } - /// - /// Observer for the 6th source observable. - /// + /// Observer for the 6th source observable. /// The parent subscription. private sealed class Observer6(Subscription parent) : IObserver { @@ -751,9 +601,7 @@ public void OnCompleted() } } - /// - /// Observer for the 7th source observable. - /// + /// Observer for the 7th source observable. /// The parent subscription. private sealed class Observer7(Subscription parent) : IObserver { @@ -774,9 +622,7 @@ public void OnCompleted() } } - /// - /// Observer for the 8th source observable. - /// + /// Observer for the 8th source observable. /// The parent subscription. private sealed class Observer8(Subscription parent) : IObserver { @@ -797,9 +643,7 @@ public void OnCompleted() } } - /// - /// Observer for the 9th source observable. - /// + /// Observer for the 9th source observable. /// The parent subscription. private sealed class Observer9(Subscription parent) : IObserver { @@ -820,9 +664,7 @@ public void OnCompleted() } } - /// - /// Observer for the 10th source observable. - /// + /// Observer for the 10th source observable. /// The parent subscription. private sealed class Observer10(Subscription parent) : IObserver { @@ -843,9 +685,7 @@ public void OnCompleted() } } - /// - /// Observer for the 11th source observable. - /// + /// Observer for the 11th source observable. /// The parent subscription. private sealed class Observer11(Subscription parent) : IObserver { @@ -866,9 +706,7 @@ public void OnCompleted() } } - /// - /// Observer for the 12th source observable. - /// + /// Observer for the 12th source observable. /// The parent subscription. private sealed class Observer12(Subscription parent) : IObserver { @@ -889,9 +727,7 @@ public void OnCompleted() } } - /// - /// Observer for the 13th source observable. - /// + /// Observer for the 13th source observable. /// The parent subscription. private sealed class Observer13(Subscription parent) : IObserver { @@ -912,9 +748,7 @@ public void OnCompleted() } } - /// - /// Observer for the 14th source observable. - /// + /// Observer for the 14th source observable. /// The parent subscription. private sealed class Observer14(Subscription parent) : IObserver { @@ -935,9 +769,7 @@ public void OnCompleted() } } - /// - /// Observer for the 15th source observable. - /// + /// Observer for the 15th source observable. /// The parent subscription. private sealed class Observer15(Subscription parent) : IObserver { @@ -958,9 +790,7 @@ public void OnCompleted() } } - /// - /// Observer for the 16th source observable. - /// + /// Observer for the 16th source observable. /// The parent subscription. private sealed class Observer16(Subscription parent) : IObserver { diff --git a/src/ReactiveUI.Binding/Observables/CombineLatest2Observable.cs b/src/ReactiveUI.Binding/Observables/CombineLatest2Observable.cs index fb92848..47cd89c 100644 --- a/src/ReactiveUI.Binding/Observables/CombineLatest2Observable.cs +++ b/src/ReactiveUI.Binding/Observables/CombineLatest2Observable.cs @@ -6,9 +6,7 @@ namespace ReactiveUI.Binding.Observables; -/// -/// Lightweight CombineLatest observable that combines the latest values from 2 source observables. -/// +/// Lightweight CombineLatest observable that combines the latest values from 2 source observables. /// The type of element 1. /// The type of element 2. /// The result element type. @@ -16,24 +14,16 @@ namespace ReactiveUI.Binding.Observables; [ExcludeFromCodeCoverage] internal sealed class CombineLatest2Observable : IObservable { - /// - /// The 1st source observable sequence. - /// + /// The 1st source observable sequence. private readonly IObservable _source1; - /// - /// The 2nd source observable sequence. - /// + /// The 2nd source observable sequence. private readonly IObservable _source2; - /// - /// The function to combine the latest values from all sources into a result. - /// + /// The function to combine the latest values from all sources into a result. private readonly Func _resultSelector; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The 1st source observable. /// The 2nd source observable. /// The function to combine the latest values. @@ -61,60 +51,33 @@ public IDisposable Subscribe(IObserver observer) return sub; } - /// - /// Manages the active subscriptions to all two source observables and emits combined results. - /// - private sealed class Subscription : IDisposable + /// Manages the active subscriptions to all two source observables and emits combined results. + /// The downstream observer. + /// The function to combine the latest values. + private sealed class Subscription(IObserver observer, Func resultSelector) : IDisposable { - /// - /// The function to combine the latest values from all sources into a result. - /// - private readonly Func _resultSelector; - - /// - /// The array of inner source subscriptions. - /// + /// The function to combine the latest values from all sources into a result. + private readonly Func _resultSelector = resultSelector; + + /// The array of inner source subscriptions. private readonly IDisposable?[] _subscriptions = new IDisposable?[2]; - /// - /// The downstream observer receiving combined results. Set to on disposal. - /// - private IObserver? _observer; + /// The downstream observer receiving combined results. Set to on disposal. + private IObserver? _observer = observer; - /// - /// The latest value received from source 1. - /// + /// The latest value received from source 1. private T1 _value1 = default!; - /// - /// The latest value received from source 2. - /// + /// The latest value received from source 2. private T2 _value2 = default!; - /// - /// Whether source 1 has emitted at least one value. - /// + /// Whether source 1 has emitted at least one value. private bool _has1; - /// - /// Whether source 2 has emitted at least one value. - /// + /// Whether source 2 has emitted at least one value. private bool _has2; - /// - /// Initializes a new instance of the class. - /// - /// The downstream observer. - /// The function to combine the latest values. - public Subscription(IObserver observer, Func resultSelector) - { - _observer = observer; - _resultSelector = resultSelector; - } - - /// - /// Subscribes to the 1st source observable. - /// + /// Subscribes to the 1st source observable. /// The 1st source observable. public void Subscribe1(IObservable source) { @@ -122,9 +85,7 @@ public void Subscribe1(IObservable source) Volatile.Write(ref _subscriptions[0], sub); } - /// - /// Subscribes to the 2nd source observable. - /// + /// Subscribes to the 2nd source observable. /// The 2nd source observable. public void Subscribe2(IObservable source) { @@ -135,7 +96,7 @@ public void Subscribe2(IObservable source) /// public void Dispose() { - if (Interlocked.Exchange(ref _observer, null) == null) + if (Interlocked.Exchange(ref _observer, null) is null) { return; } @@ -146,9 +107,7 @@ public void Dispose() } } - /// - /// Emits the combined result if all sources have produced at least one value. - /// + /// Emits the combined result if all sources have produced at least one value. private void TryEmit() { if (!_has1 || !_has2) @@ -156,12 +115,10 @@ private void TryEmit() return; } - _observer?.OnNext(_resultSelector(_value1, _value2)); + Volatile.Read(ref _observer)?.OnNext(_resultSelector(_value1, _value2)); } - /// - /// Observer for the 1st source observable. - /// + /// Observer for the 1st source observable. /// The parent subscription. private sealed class Observer1(Subscription parent) : IObserver { @@ -182,9 +139,7 @@ public void OnCompleted() } } - /// - /// Observer for the 2nd source observable. - /// + /// Observer for the 2nd source observable. /// The parent subscription. private sealed class Observer2(Subscription parent) : IObserver { diff --git a/src/ReactiveUI.Binding/Observables/CombineLatest3Observable.cs b/src/ReactiveUI.Binding/Observables/CombineLatest3Observable.cs index 8ac700b..4906dcd 100644 --- a/src/ReactiveUI.Binding/Observables/CombineLatest3Observable.cs +++ b/src/ReactiveUI.Binding/Observables/CombineLatest3Observable.cs @@ -6,9 +6,7 @@ namespace ReactiveUI.Binding.Observables; -/// -/// Lightweight CombineLatest observable that combines the latest values from 3 source observables. -/// +/// Lightweight CombineLatest observable that combines the latest values from 3 source observables. /// The type of element 1. /// The type of element 2. /// The type of element 3. @@ -17,29 +15,19 @@ namespace ReactiveUI.Binding.Observables; [ExcludeFromCodeCoverage] internal sealed class CombineLatest3Observable : IObservable { - /// - /// The 1st source observable sequence. - /// + /// The 1st source observable sequence. private readonly IObservable _source1; - /// - /// The 2nd source observable sequence. - /// + /// The 2nd source observable sequence. private readonly IObservable _source2; - /// - /// The 3rd source observable sequence. - /// + /// The 3rd source observable sequence. private readonly IObservable _source3; - /// - /// The function to combine the latest values from all sources into a result. - /// + /// The function to combine the latest values from all sources into a result. private readonly Func _resultSelector; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The 1st source observable. /// The 2nd source observable. /// The 3rd source observable. @@ -72,75 +60,42 @@ public IDisposable Subscribe(IObserver observer) return sub; } - /// - /// Manages the active subscriptions to all three source observables and emits combined results. - /// - private sealed class Subscription : IDisposable + /// Manages the active subscriptions to all three source observables and emits combined results. + /// The downstream observer. + /// The function to combine the latest values. + private sealed class Subscription(IObserver observer, Func resultSelector) : IDisposable { - /// - /// The subscription array index for source 3. - /// + /// The subscription array index for source 3. private const int Source3Index = 2; - /// - /// The function to combine the latest values from all sources into a result. - /// - private readonly Func _resultSelector; + /// The function to combine the latest values from all sources into a result. + private readonly Func _resultSelector = resultSelector; - /// - /// The array of inner source subscriptions. - /// + /// The array of inner source subscriptions. private readonly IDisposable?[] _subscriptions = new IDisposable?[3]; - /// - /// The downstream observer receiving combined results. Set to on disposal. - /// - private IObserver? _observer; + /// The downstream observer receiving combined results. Set to on disposal. + private IObserver? _observer = observer; - /// - /// The latest value received from source 1. - /// + /// The latest value received from source 1. private T1 _value1 = default!; - /// - /// The latest value received from source 2. - /// + /// The latest value received from source 2. private T2 _value2 = default!; - /// - /// The latest value received from source 3. - /// + /// The latest value received from source 3. private T3 _value3 = default!; - /// - /// Whether source 1 has emitted at least one value. - /// + /// Whether source 1 has emitted at least one value. private bool _has1; - /// - /// Whether source 2 has emitted at least one value. - /// + /// Whether source 2 has emitted at least one value. private bool _has2; - /// - /// Whether source 3 has emitted at least one value. - /// + /// Whether source 3 has emitted at least one value. private bool _has3; - /// - /// Initializes a new instance of the class. - /// - /// The downstream observer. - /// The function to combine the latest values. - public Subscription(IObserver observer, Func resultSelector) - { - _observer = observer; - _resultSelector = resultSelector; - } - - /// - /// Subscribes to the 1st source observable. - /// + /// Subscribes to the 1st source observable. /// The 1st source observable. public void Subscribe1(IObservable source) { @@ -148,9 +103,7 @@ public void Subscribe1(IObservable source) Volatile.Write(ref _subscriptions[0], sub); } - /// - /// Subscribes to the 2nd source observable. - /// + /// Subscribes to the 2nd source observable. /// The 2nd source observable. public void Subscribe2(IObservable source) { @@ -158,9 +111,7 @@ public void Subscribe2(IObservable source) Volatile.Write(ref _subscriptions[1], sub); } - /// - /// Subscribes to the 3rd source observable. - /// + /// Subscribes to the 3rd source observable. /// The 3rd source observable. public void Subscribe3(IObservable source) { @@ -171,7 +122,7 @@ public void Subscribe3(IObservable source) /// public void Dispose() { - if (Interlocked.Exchange(ref _observer, null) == null) + if (Interlocked.Exchange(ref _observer, null) is null) { return; } @@ -182,9 +133,7 @@ public void Dispose() } } - /// - /// Emits the combined result if all sources have produced at least one value. - /// + /// Emits the combined result if all sources have produced at least one value. private void TryEmit() { if (!_has1 || !_has2 || !_has3) @@ -192,12 +141,10 @@ private void TryEmit() return; } - _observer?.OnNext(_resultSelector(_value1, _value2, _value3)); + Volatile.Read(ref _observer)?.OnNext(_resultSelector(_value1, _value2, _value3)); } - /// - /// Observer for the 1st source observable. - /// + /// Observer for the 1st source observable. /// The parent subscription. private sealed class Observer1(Subscription parent) : IObserver { @@ -218,9 +165,7 @@ public void OnCompleted() } } - /// - /// Observer for the 2nd source observable. - /// + /// Observer for the 2nd source observable. /// The parent subscription. private sealed class Observer2(Subscription parent) : IObserver { @@ -241,9 +186,7 @@ public void OnCompleted() } } - /// - /// Observer for the 3rd source observable. - /// + /// Observer for the 3rd source observable. /// The parent subscription. private sealed class Observer3(Subscription parent) : IObserver { diff --git a/src/ReactiveUI.Binding/Observables/CombineLatest4Observable.cs b/src/ReactiveUI.Binding/Observables/CombineLatest4Observable.cs index 49d7c5c..07ae38a 100644 --- a/src/ReactiveUI.Binding/Observables/CombineLatest4Observable.cs +++ b/src/ReactiveUI.Binding/Observables/CombineLatest4Observable.cs @@ -6,9 +6,7 @@ namespace ReactiveUI.Binding.Observables; -/// -/// Lightweight CombineLatest observable that combines the latest values from 4 source observables. -/// +/// Lightweight CombineLatest observable that combines the latest values from 4 source observables. /// The type of element 1. /// The type of element 2. /// The type of element 3. @@ -18,34 +16,22 @@ namespace ReactiveUI.Binding.Observables; [ExcludeFromCodeCoverage] internal sealed class CombineLatest4Observable : IObservable { - /// - /// The 1st source observable sequence. - /// + /// The 1st source observable sequence. private readonly IObservable _source1; - /// - /// The 2nd source observable sequence. - /// + /// The 2nd source observable sequence. private readonly IObservable _source2; - /// - /// The 3rd source observable sequence. - /// + /// The 3rd source observable sequence. private readonly IObservable _source3; - /// - /// The 4th source observable sequence. - /// + /// The 4th source observable sequence. private readonly IObservable _source4; - /// - /// The function to combine the latest values from all sources into a result. - /// + /// The function to combine the latest values from all sources into a result. private readonly Func _resultSelector; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The 1st source observable. /// The 2nd source observable. /// The 3rd source observable. @@ -83,90 +69,51 @@ public IDisposable Subscribe(IObserver observer) return sub; } - /// - /// Manages the active subscriptions to all four source observables and emits combined results. - /// - private sealed class Subscription : IDisposable + /// Manages the active subscriptions to all four source observables and emits combined results. + /// The downstream observer. + /// The function to combine the latest values. + private sealed class Subscription(IObserver observer, Func resultSelector) : IDisposable { - /// - /// The subscription array index for source 3. - /// + /// The subscription array index for source 3. private const int Source3Index = 2; - /// - /// The subscription array index for source 4. - /// + /// The subscription array index for source 4. private const int Source4Index = 3; - /// - /// The function to combine the latest values from all sources into a result. - /// - private readonly Func _resultSelector; + /// The function to combine the latest values from all sources into a result. + private readonly Func _resultSelector = resultSelector; - /// - /// The array of inner source subscriptions. - /// + /// The array of inner source subscriptions. private readonly IDisposable?[] _subscriptions = new IDisposable?[4]; - /// - /// The downstream observer receiving combined results. Set to on disposal. - /// - private IObserver? _observer; + /// The downstream observer receiving combined results. Set to on disposal. + private IObserver? _observer = observer; - /// - /// The latest value received from source 1. - /// + /// The latest value received from source 1. private T1 _value1 = default!; - /// - /// The latest value received from source 2. - /// + /// The latest value received from source 2. private T2 _value2 = default!; - /// - /// The latest value received from source 3. - /// + /// The latest value received from source 3. private T3 _value3 = default!; - /// - /// The latest value received from source 4. - /// + /// The latest value received from source 4. private T4 _value4 = default!; - /// - /// Whether source 1 has emitted at least one value. - /// + /// Whether source 1 has emitted at least one value. private bool _has1; - /// - /// Whether source 2 has emitted at least one value. - /// + /// Whether source 2 has emitted at least one value. private bool _has2; - /// - /// Whether source 3 has emitted at least one value. - /// + /// Whether source 3 has emitted at least one value. private bool _has3; - /// - /// Whether source 4 has emitted at least one value. - /// + /// Whether source 4 has emitted at least one value. private bool _has4; - /// - /// Initializes a new instance of the class. - /// - /// The downstream observer. - /// The function to combine the latest values. - public Subscription(IObserver observer, Func resultSelector) - { - _observer = observer; - _resultSelector = resultSelector; - } - - /// - /// Subscribes to the 1st source observable. - /// + /// Subscribes to the 1st source observable. /// The 1st source observable. public void Subscribe1(IObservable source) { @@ -174,9 +121,7 @@ public void Subscribe1(IObservable source) Volatile.Write(ref _subscriptions[0], sub); } - /// - /// Subscribes to the 2nd source observable. - /// + /// Subscribes to the 2nd source observable. /// The 2nd source observable. public void Subscribe2(IObservable source) { @@ -184,9 +129,7 @@ public void Subscribe2(IObservable source) Volatile.Write(ref _subscriptions[1], sub); } - /// - /// Subscribes to the 3rd source observable. - /// + /// Subscribes to the 3rd source observable. /// The 3rd source observable. public void Subscribe3(IObservable source) { @@ -194,9 +137,7 @@ public void Subscribe3(IObservable source) Volatile.Write(ref _subscriptions[Source3Index], sub); } - /// - /// Subscribes to the 4th source observable. - /// + /// Subscribes to the 4th source observable. /// The 4th source observable. public void Subscribe4(IObservable source) { @@ -207,7 +148,7 @@ public void Subscribe4(IObservable source) /// public void Dispose() { - if (Interlocked.Exchange(ref _observer, null) == null) + if (Interlocked.Exchange(ref _observer, null) is null) { return; } @@ -218,9 +159,7 @@ public void Dispose() } } - /// - /// Emits the combined result if all sources have produced at least one value. - /// + /// Emits the combined result if all sources have produced at least one value. private void TryEmit() { if (!_has1 || !_has2 || !_has3 || !_has4) @@ -228,12 +167,10 @@ private void TryEmit() return; } - _observer?.OnNext(_resultSelector(_value1, _value2, _value3, _value4)); + Volatile.Read(ref _observer)?.OnNext(_resultSelector(_value1, _value2, _value3, _value4)); } - /// - /// Observer for the 1st source observable. - /// + /// Observer for the 1st source observable. /// The parent subscription. private sealed class Observer1(Subscription parent) : IObserver { @@ -254,9 +191,7 @@ public void OnCompleted() } } - /// - /// Observer for the 2nd source observable. - /// + /// Observer for the 2nd source observable. /// The parent subscription. private sealed class Observer2(Subscription parent) : IObserver { @@ -277,9 +212,7 @@ public void OnCompleted() } } - /// - /// Observer for the 3rd source observable. - /// + /// Observer for the 3rd source observable. /// The parent subscription. private sealed class Observer3(Subscription parent) : IObserver { @@ -300,9 +233,7 @@ public void OnCompleted() } } - /// - /// Observer for the 4th source observable. - /// + /// Observer for the 4th source observable. /// The parent subscription. private sealed class Observer4(Subscription parent) : IObserver { diff --git a/src/ReactiveUI.Binding/Observables/CombineLatest5Observable.cs b/src/ReactiveUI.Binding/Observables/CombineLatest5Observable.cs index eb2f0ad..befef78 100644 --- a/src/ReactiveUI.Binding/Observables/CombineLatest5Observable.cs +++ b/src/ReactiveUI.Binding/Observables/CombineLatest5Observable.cs @@ -6,9 +6,7 @@ namespace ReactiveUI.Binding.Observables; -/// -/// Lightweight CombineLatest observable that combines the latest values from 5 source observables. -/// +/// Lightweight CombineLatest observable that combines the latest values from 5 source observables. /// The type of element 1. /// The type of element 2. /// The type of element 3. @@ -19,39 +17,25 @@ namespace ReactiveUI.Binding.Observables; [ExcludeFromCodeCoverage] internal sealed class CombineLatest5Observable : IObservable { - /// - /// The 1st source observable sequence. - /// + /// The 1st source observable sequence. private readonly IObservable _source1; - /// - /// The 2nd source observable sequence. - /// + /// The 2nd source observable sequence. private readonly IObservable _source2; - /// - /// The 3rd source observable sequence. - /// + /// The 3rd source observable sequence. private readonly IObservable _source3; - /// - /// The 4th source observable sequence. - /// + /// The 4th source observable sequence. private readonly IObservable _source4; - /// - /// The 5th source observable sequence. - /// + /// The 5th source observable sequence. private readonly IObservable _source5; - /// - /// The function to combine the latest values from all sources into a result. - /// + /// The function to combine the latest values from all sources into a result. private readonly Func _resultSelector; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The 1st source observable. /// The 2nd source observable. /// The 3rd source observable. @@ -94,105 +78,60 @@ public IDisposable Subscribe(IObserver observer) return sub; } - /// - /// Manages the active subscriptions to all five source observables and emits combined results. - /// - private sealed class Subscription : IDisposable + /// Manages the active subscriptions to all five source observables and emits combined results. + /// The downstream observer. + /// The function to combine the latest values. + private sealed class Subscription(IObserver observer, Func resultSelector) : IDisposable { - /// - /// The subscription array index for source 3. - /// + /// The subscription array index for source 3. private const int Source3Index = 2; - /// - /// The subscription array index for source 4. - /// + /// The subscription array index for source 4. private const int Source4Index = 3; - /// - /// The subscription array index for source 5. - /// + /// The subscription array index for source 5. private const int Source5Index = 4; - /// - /// The function to combine the latest values from all sources into a result. - /// - private readonly Func _resultSelector; + /// The function to combine the latest values from all sources into a result. + private readonly Func _resultSelector = resultSelector; - /// - /// The array of inner source subscriptions. - /// + /// The array of inner source subscriptions. private readonly IDisposable?[] _subscriptions = new IDisposable?[5]; - /// - /// The downstream observer receiving combined results. Set to on disposal. - /// - private IObserver? _observer; + /// The downstream observer receiving combined results. Set to on disposal. + private IObserver? _observer = observer; - /// - /// The latest value received from source 1. - /// + /// The latest value received from source 1. private T1 _value1 = default!; - /// - /// The latest value received from source 2. - /// + /// The latest value received from source 2. private T2 _value2 = default!; - /// - /// The latest value received from source 3. - /// + /// The latest value received from source 3. private T3 _value3 = default!; - /// - /// The latest value received from source 4. - /// + /// The latest value received from source 4. private T4 _value4 = default!; - /// - /// The latest value received from source 5. - /// + /// The latest value received from source 5. private T5 _value5 = default!; - /// - /// Whether source 1 has emitted at least one value. - /// + /// Whether source 1 has emitted at least one value. private bool _has1; - /// - /// Whether source 2 has emitted at least one value. - /// + /// Whether source 2 has emitted at least one value. private bool _has2; - /// - /// Whether source 3 has emitted at least one value. - /// + /// Whether source 3 has emitted at least one value. private bool _has3; - /// - /// Whether source 4 has emitted at least one value. - /// + /// Whether source 4 has emitted at least one value. private bool _has4; - /// - /// Whether source 5 has emitted at least one value. - /// + /// Whether source 5 has emitted at least one value. private bool _has5; - /// - /// Initializes a new instance of the class. - /// - /// The downstream observer. - /// The function to combine the latest values. - public Subscription(IObserver observer, Func resultSelector) - { - _observer = observer; - _resultSelector = resultSelector; - } - - /// - /// Subscribes to the 1st source observable. - /// + /// Subscribes to the 1st source observable. /// The 1st source observable. public void Subscribe1(IObservable source) { @@ -200,9 +139,7 @@ public void Subscribe1(IObservable source) Volatile.Write(ref _subscriptions[0], sub); } - /// - /// Subscribes to the 2nd source observable. - /// + /// Subscribes to the 2nd source observable. /// The 2nd source observable. public void Subscribe2(IObservable source) { @@ -210,9 +147,7 @@ public void Subscribe2(IObservable source) Volatile.Write(ref _subscriptions[1], sub); } - /// - /// Subscribes to the 3rd source observable. - /// + /// Subscribes to the 3rd source observable. /// The 3rd source observable. public void Subscribe3(IObservable source) { @@ -220,9 +155,7 @@ public void Subscribe3(IObservable source) Volatile.Write(ref _subscriptions[Source3Index], sub); } - /// - /// Subscribes to the 4th source observable. - /// + /// Subscribes to the 4th source observable. /// The 4th source observable. public void Subscribe4(IObservable source) { @@ -230,9 +163,7 @@ public void Subscribe4(IObservable source) Volatile.Write(ref _subscriptions[Source4Index], sub); } - /// - /// Subscribes to the 5th source observable. - /// + /// Subscribes to the 5th source observable. /// The 5th source observable. public void Subscribe5(IObservable source) { @@ -243,7 +174,7 @@ public void Subscribe5(IObservable source) /// public void Dispose() { - if (Interlocked.Exchange(ref _observer, null) == null) + if (Interlocked.Exchange(ref _observer, null) is null) { return; } @@ -254,9 +185,7 @@ public void Dispose() } } - /// - /// Emits the combined result if all sources have produced at least one value. - /// + /// Emits the combined result if all sources have produced at least one value. private void TryEmit() { if (!_has1 || !_has2 || !_has3 || !_has4 || !_has5) @@ -264,12 +193,10 @@ private void TryEmit() return; } - _observer?.OnNext(_resultSelector(_value1, _value2, _value3, _value4, _value5)); + Volatile.Read(ref _observer)?.OnNext(_resultSelector(_value1, _value2, _value3, _value4, _value5)); } - /// - /// Observer for the 1st source observable. - /// + /// Observer for the 1st source observable. /// The parent subscription. private sealed class Observer1(Subscription parent) : IObserver { @@ -290,9 +217,7 @@ public void OnCompleted() } } - /// - /// Observer for the 2nd source observable. - /// + /// Observer for the 2nd source observable. /// The parent subscription. private sealed class Observer2(Subscription parent) : IObserver { @@ -313,9 +238,7 @@ public void OnCompleted() } } - /// - /// Observer for the 3rd source observable. - /// + /// Observer for the 3rd source observable. /// The parent subscription. private sealed class Observer3(Subscription parent) : IObserver { @@ -336,9 +259,7 @@ public void OnCompleted() } } - /// - /// Observer for the 4th source observable. - /// + /// Observer for the 4th source observable. /// The parent subscription. private sealed class Observer4(Subscription parent) : IObserver { @@ -359,9 +280,7 @@ public void OnCompleted() } } - /// - /// Observer for the 5th source observable. - /// + /// Observer for the 5th source observable. /// The parent subscription. private sealed class Observer5(Subscription parent) : IObserver { diff --git a/src/ReactiveUI.Binding/Observables/CombineLatest6Observable.cs b/src/ReactiveUI.Binding/Observables/CombineLatest6Observable.cs index 538f48c..7ed1900 100644 --- a/src/ReactiveUI.Binding/Observables/CombineLatest6Observable.cs +++ b/src/ReactiveUI.Binding/Observables/CombineLatest6Observable.cs @@ -6,9 +6,7 @@ namespace ReactiveUI.Binding.Observables; -/// -/// Lightweight CombineLatest observable that combines the latest values from 6 source observables. -/// +/// Lightweight CombineLatest observable that combines the latest values from 6 source observables. /// The type of element 1. /// The type of element 2. /// The type of element 3. @@ -20,44 +18,28 @@ namespace ReactiveUI.Binding.Observables; [ExcludeFromCodeCoverage] internal sealed class CombineLatest6Observable : IObservable { - /// - /// The 1st source observable sequence. - /// + /// The 1st source observable sequence. private readonly IObservable _source1; - /// - /// The 2nd source observable sequence. - /// + /// The 2nd source observable sequence. private readonly IObservable _source2; - /// - /// The 3rd source observable sequence. - /// + /// The 3rd source observable sequence. private readonly IObservable _source3; - /// - /// The 4th source observable sequence. - /// + /// The 4th source observable sequence. private readonly IObservable _source4; - /// - /// The 5th source observable sequence. - /// + /// The 5th source observable sequence. private readonly IObservable _source5; - /// - /// The 6th source observable sequence. - /// + /// The 6th source observable sequence. private readonly IObservable _source6; - /// - /// The function to combine the latest values from all sources into a result. - /// + /// The function to combine the latest values from all sources into a result. private readonly Func _resultSelector; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The 1st source observable. /// The 2nd source observable. /// The 3rd source observable. @@ -105,120 +87,69 @@ public IDisposable Subscribe(IObserver observer) return sub; } - /// - /// Manages the active subscriptions to all six source observables and emits combined results. - /// - private sealed class Subscription : IDisposable + /// Manages the active subscriptions to all six source observables and emits combined results. + /// The downstream observer. + /// The function to combine the latest values. + private sealed class Subscription(IObserver observer, Func resultSelector) : IDisposable { - /// - /// The subscription array index for source 3. - /// + /// The subscription array index for source 3. private const int Source3Index = 2; - /// - /// The subscription array index for source 4. - /// + /// The subscription array index for source 4. private const int Source4Index = 3; - /// - /// The subscription array index for source 5. - /// + /// The subscription array index for source 5. private const int Source5Index = 4; - /// - /// The subscription array index for source 6. - /// + /// The subscription array index for source 6. private const int Source6Index = 5; - /// - /// The function to combine the latest values from all sources into a result. - /// - private readonly Func _resultSelector; + /// The function to combine the latest values from all sources into a result. + private readonly Func _resultSelector = resultSelector; - /// - /// The array of inner source subscriptions. - /// + /// The array of inner source subscriptions. private readonly IDisposable?[] _subscriptions = new IDisposable?[6]; - /// - /// The downstream observer receiving combined results. Set to on disposal. - /// - private IObserver? _observer; + /// The downstream observer receiving combined results. Set to on disposal. + private IObserver? _observer = observer; - /// - /// The latest value received from source 1. - /// + /// The latest value received from source 1. private T1 _value1 = default!; - /// - /// The latest value received from source 2. - /// + /// The latest value received from source 2. private T2 _value2 = default!; - /// - /// The latest value received from source 3. - /// + /// The latest value received from source 3. private T3 _value3 = default!; - /// - /// The latest value received from source 4. - /// + /// The latest value received from source 4. private T4 _value4 = default!; - /// - /// The latest value received from source 5. - /// + /// The latest value received from source 5. private T5 _value5 = default!; - /// - /// The latest value received from source 6. - /// + /// The latest value received from source 6. private T6 _value6 = default!; - /// - /// Whether source 1 has emitted at least one value. - /// + /// Whether source 1 has emitted at least one value. private bool _has1; - /// - /// Whether source 2 has emitted at least one value. - /// + /// Whether source 2 has emitted at least one value. private bool _has2; - /// - /// Whether source 3 has emitted at least one value. - /// + /// Whether source 3 has emitted at least one value. private bool _has3; - /// - /// Whether source 4 has emitted at least one value. - /// + /// Whether source 4 has emitted at least one value. private bool _has4; - /// - /// Whether source 5 has emitted at least one value. - /// + /// Whether source 5 has emitted at least one value. private bool _has5; - /// - /// Whether source 6 has emitted at least one value. - /// + /// Whether source 6 has emitted at least one value. private bool _has6; - /// - /// Initializes a new instance of the class. - /// - /// The downstream observer. - /// The function to combine the latest values. - public Subscription(IObserver observer, Func resultSelector) - { - _observer = observer; - _resultSelector = resultSelector; - } - - /// - /// Subscribes to the 1st source observable. - /// + /// Subscribes to the 1st source observable. /// The 1st source observable. public void Subscribe1(IObservable source) { @@ -226,9 +157,7 @@ public void Subscribe1(IObservable source) Volatile.Write(ref _subscriptions[0], sub); } - /// - /// Subscribes to the 2nd source observable. - /// + /// Subscribes to the 2nd source observable. /// The 2nd source observable. public void Subscribe2(IObservable source) { @@ -236,9 +165,7 @@ public void Subscribe2(IObservable source) Volatile.Write(ref _subscriptions[1], sub); } - /// - /// Subscribes to the 3rd source observable. - /// + /// Subscribes to the 3rd source observable. /// The 3rd source observable. public void Subscribe3(IObservable source) { @@ -246,9 +173,7 @@ public void Subscribe3(IObservable source) Volatile.Write(ref _subscriptions[Source3Index], sub); } - /// - /// Subscribes to the 4th source observable. - /// + /// Subscribes to the 4th source observable. /// The 4th source observable. public void Subscribe4(IObservable source) { @@ -256,9 +181,7 @@ public void Subscribe4(IObservable source) Volatile.Write(ref _subscriptions[Source4Index], sub); } - /// - /// Subscribes to the 5th source observable. - /// + /// Subscribes to the 5th source observable. /// The 5th source observable. public void Subscribe5(IObservable source) { @@ -266,9 +189,7 @@ public void Subscribe5(IObservable source) Volatile.Write(ref _subscriptions[Source5Index], sub); } - /// - /// Subscribes to the 6th source observable. - /// + /// Subscribes to the 6th source observable. /// The 6th source observable. public void Subscribe6(IObservable source) { @@ -279,7 +200,7 @@ public void Subscribe6(IObservable source) /// public void Dispose() { - if (Interlocked.Exchange(ref _observer, null) == null) + if (Interlocked.Exchange(ref _observer, null) is null) { return; } @@ -290,9 +211,7 @@ public void Dispose() } } - /// - /// Emits the combined result if all sources have produced at least one value. - /// + /// Emits the combined result if all sources have produced at least one value. private void TryEmit() { if (!_has1 || !_has2 || !_has3 || !_has4 || !_has5 || !_has6) @@ -300,12 +219,10 @@ private void TryEmit() return; } - _observer?.OnNext(_resultSelector(_value1, _value2, _value3, _value4, _value5, _value6)); + Volatile.Read(ref _observer)?.OnNext(_resultSelector(_value1, _value2, _value3, _value4, _value5, _value6)); } - /// - /// Observer for the 1st source observable. - /// + /// Observer for the 1st source observable. /// The parent subscription. private sealed class Observer1(Subscription parent) : IObserver { @@ -326,9 +243,7 @@ public void OnCompleted() } } - /// - /// Observer for the 2nd source observable. - /// + /// Observer for the 2nd source observable. /// The parent subscription. private sealed class Observer2(Subscription parent) : IObserver { @@ -349,9 +264,7 @@ public void OnCompleted() } } - /// - /// Observer for the 3rd source observable. - /// + /// Observer for the 3rd source observable. /// The parent subscription. private sealed class Observer3(Subscription parent) : IObserver { @@ -372,9 +285,7 @@ public void OnCompleted() } } - /// - /// Observer for the 4th source observable. - /// + /// Observer for the 4th source observable. /// The parent subscription. private sealed class Observer4(Subscription parent) : IObserver { @@ -395,9 +306,7 @@ public void OnCompleted() } } - /// - /// Observer for the 5th source observable. - /// + /// Observer for the 5th source observable. /// The parent subscription. private sealed class Observer5(Subscription parent) : IObserver { @@ -418,9 +327,7 @@ public void OnCompleted() } } - /// - /// Observer for the 6th source observable. - /// + /// Observer for the 6th source observable. /// The parent subscription. private sealed class Observer6(Subscription parent) : IObserver { diff --git a/src/ReactiveUI.Binding/Observables/CombineLatest7Observable.cs b/src/ReactiveUI.Binding/Observables/CombineLatest7Observable.cs index c129a20..ee7e635 100644 --- a/src/ReactiveUI.Binding/Observables/CombineLatest7Observable.cs +++ b/src/ReactiveUI.Binding/Observables/CombineLatest7Observable.cs @@ -6,9 +6,7 @@ namespace ReactiveUI.Binding.Observables; -/// -/// Lightweight CombineLatest observable that combines the latest values from 7 source observables. -/// +/// Lightweight CombineLatest observable that combines the latest values from 7 source observables. /// The type of element 1. /// The type of element 2. /// The type of element 3. @@ -19,55 +17,33 @@ namespace ReactiveUI.Binding.Observables; /// The result element type. [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] -[SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "Deliberately large arity intrinsic to the N-argument binding/observable API surface.")] internal sealed class CombineLatest7Observable : IObservable { - /// - /// The 1st source observable sequence. - /// + /// The 1st source observable sequence. private readonly IObservable _source1; - /// - /// The 2nd source observable sequence. - /// + /// The 2nd source observable sequence. private readonly IObservable _source2; - /// - /// The 3rd source observable sequence. - /// + /// The 3rd source observable sequence. private readonly IObservable _source3; - /// - /// The 4th source observable sequence. - /// + /// The 4th source observable sequence. private readonly IObservable _source4; - /// - /// The 5th source observable sequence. - /// + /// The 5th source observable sequence. private readonly IObservable _source5; - /// - /// The 6th source observable sequence. - /// + /// The 6th source observable sequence. private readonly IObservable _source6; - /// - /// The 7th source observable sequence. - /// + /// The 7th source observable sequence. private readonly IObservable _source7; - /// - /// The function to combine the latest values from all sources into a result. - /// + /// The function to combine the latest values from all sources into a result. private readonly Func _resultSelector; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The 1st source observable. /// The 2nd source observable. /// The 3rd source observable. @@ -76,6 +52,7 @@ internal sealed class CombineLatest7ObservableThe 6th source observable. /// The 7th source observable. /// The function to combine the latest values. + [SuppressMessage("Design", "SST1472:Signatures should not declare too many parameters", Justification = "Parameter count is intrinsic to the fixed CombineLatest arity.")] public CombineLatest7Observable( IObservable source1, IObservable source2, @@ -120,135 +97,78 @@ public IDisposable Subscribe(IObserver observer) return sub; } - /// - /// Manages the active subscriptions to all seven source observables and emits combined results. - /// - private sealed class Subscription : IDisposable + /// Manages the active subscriptions to all seven source observables and emits combined results. + /// The downstream observer. + /// The function to combine the latest values. + private sealed class Subscription(IObserver observer, Func resultSelector) : IDisposable { - /// - /// The subscription array index for source 3. - /// + /// The subscription array index for source 3. private const int Source3Index = 2; - /// - /// The subscription array index for source 4. - /// + /// The subscription array index for source 4. private const int Source4Index = 3; - /// - /// The subscription array index for source 5. - /// + /// The subscription array index for source 5. private const int Source5Index = 4; - /// - /// The subscription array index for source 6. - /// + /// The subscription array index for source 6. private const int Source6Index = 5; - /// - /// The subscription array index for source 7. - /// + /// The subscription array index for source 7. private const int Source7Index = 6; - /// - /// The function to combine the latest values from all sources into a result. - /// - private readonly Func _resultSelector; + /// The function to combine the latest values from all sources into a result. + private readonly Func _resultSelector = resultSelector; - /// - /// The array of inner source subscriptions. - /// + /// The array of inner source subscriptions. private readonly IDisposable?[] _subscriptions = new IDisposable?[7]; - /// - /// The downstream observer receiving combined results. Set to on disposal. - /// - private IObserver? _observer; + /// The downstream observer receiving combined results. Set to on disposal. + private IObserver? _observer = observer; - /// - /// The latest value received from source 1. - /// + /// The latest value received from source 1. private T1 _value1 = default!; - /// - /// The latest value received from source 2. - /// + /// The latest value received from source 2. private T2 _value2 = default!; - /// - /// The latest value received from source 3. - /// + /// The latest value received from source 3. private T3 _value3 = default!; - /// - /// The latest value received from source 4. - /// + /// The latest value received from source 4. private T4 _value4 = default!; - /// - /// The latest value received from source 5. - /// + /// The latest value received from source 5. private T5 _value5 = default!; - /// - /// The latest value received from source 6. - /// + /// The latest value received from source 6. private T6 _value6 = default!; - /// - /// The latest value received from source 7. - /// + /// The latest value received from source 7. private T7 _value7 = default!; - /// - /// Whether source 1 has emitted at least one value. - /// + /// Whether source 1 has emitted at least one value. private bool _has1; - /// - /// Whether source 2 has emitted at least one value. - /// + /// Whether source 2 has emitted at least one value. private bool _has2; - /// - /// Whether source 3 has emitted at least one value. - /// + /// Whether source 3 has emitted at least one value. private bool _has3; - /// - /// Whether source 4 has emitted at least one value. - /// + /// Whether source 4 has emitted at least one value. private bool _has4; - /// - /// Whether source 5 has emitted at least one value. - /// + /// Whether source 5 has emitted at least one value. private bool _has5; - /// - /// Whether source 6 has emitted at least one value. - /// + /// Whether source 6 has emitted at least one value. private bool _has6; - /// - /// Whether source 7 has emitted at least one value. - /// + /// Whether source 7 has emitted at least one value. private bool _has7; - /// - /// Initializes a new instance of the class. - /// - /// The downstream observer. - /// The function to combine the latest values. - public Subscription(IObserver observer, Func resultSelector) - { - _observer = observer; - _resultSelector = resultSelector; - } - - /// - /// Subscribes to the 1st source observable. - /// + /// Subscribes to the 1st source observable. /// The 1st source observable. public void Subscribe1(IObservable source) { @@ -256,9 +176,7 @@ public void Subscribe1(IObservable source) Volatile.Write(ref _subscriptions[0], sub); } - /// - /// Subscribes to the 2nd source observable. - /// + /// Subscribes to the 2nd source observable. /// The 2nd source observable. public void Subscribe2(IObservable source) { @@ -266,9 +184,7 @@ public void Subscribe2(IObservable source) Volatile.Write(ref _subscriptions[1], sub); } - /// - /// Subscribes to the 3rd source observable. - /// + /// Subscribes to the 3rd source observable. /// The 3rd source observable. public void Subscribe3(IObservable source) { @@ -276,9 +192,7 @@ public void Subscribe3(IObservable source) Volatile.Write(ref _subscriptions[Source3Index], sub); } - /// - /// Subscribes to the 4th source observable. - /// + /// Subscribes to the 4th source observable. /// The 4th source observable. public void Subscribe4(IObservable source) { @@ -286,9 +200,7 @@ public void Subscribe4(IObservable source) Volatile.Write(ref _subscriptions[Source4Index], sub); } - /// - /// Subscribes to the 5th source observable. - /// + /// Subscribes to the 5th source observable. /// The 5th source observable. public void Subscribe5(IObservable source) { @@ -296,9 +208,7 @@ public void Subscribe5(IObservable source) Volatile.Write(ref _subscriptions[Source5Index], sub); } - /// - /// Subscribes to the 6th source observable. - /// + /// Subscribes to the 6th source observable. /// The 6th source observable. public void Subscribe6(IObservable source) { @@ -306,9 +216,7 @@ public void Subscribe6(IObservable source) Volatile.Write(ref _subscriptions[Source6Index], sub); } - /// - /// Subscribes to the 7th source observable. - /// + /// Subscribes to the 7th source observable. /// The 7th source observable. public void Subscribe7(IObservable source) { @@ -319,7 +227,7 @@ public void Subscribe7(IObservable source) /// public void Dispose() { - if (Interlocked.Exchange(ref _observer, null) == null) + if (Interlocked.Exchange(ref _observer, null) is null) { return; } @@ -330,9 +238,7 @@ public void Dispose() } } - /// - /// Emits the combined result if all sources have produced at least one value. - /// + /// Emits the combined result if all sources have produced at least one value. private void TryEmit() { if (!_has1 || !_has2 || !_has3 || !_has4 || !_has5 || !_has6 || !_has7) @@ -340,12 +246,10 @@ private void TryEmit() return; } - _observer?.OnNext(_resultSelector(_value1, _value2, _value3, _value4, _value5, _value6, _value7)); + Volatile.Read(ref _observer)?.OnNext(_resultSelector(_value1, _value2, _value3, _value4, _value5, _value6, _value7)); } - /// - /// Observer for the 1st source observable. - /// + /// Observer for the 1st source observable. /// The parent subscription. private sealed class Observer1(Subscription parent) : IObserver { @@ -366,9 +270,7 @@ public void OnCompleted() } } - /// - /// Observer for the 2nd source observable. - /// + /// Observer for the 2nd source observable. /// The parent subscription. private sealed class Observer2(Subscription parent) : IObserver { @@ -389,9 +291,7 @@ public void OnCompleted() } } - /// - /// Observer for the 3rd source observable. - /// + /// Observer for the 3rd source observable. /// The parent subscription. private sealed class Observer3(Subscription parent) : IObserver { @@ -412,9 +312,7 @@ public void OnCompleted() } } - /// - /// Observer for the 4th source observable. - /// + /// Observer for the 4th source observable. /// The parent subscription. private sealed class Observer4(Subscription parent) : IObserver { @@ -435,9 +333,7 @@ public void OnCompleted() } } - /// - /// Observer for the 5th source observable. - /// + /// Observer for the 5th source observable. /// The parent subscription. private sealed class Observer5(Subscription parent) : IObserver { @@ -458,9 +354,7 @@ public void OnCompleted() } } - /// - /// Observer for the 6th source observable. - /// + /// Observer for the 6th source observable. /// The parent subscription. private sealed class Observer6(Subscription parent) : IObserver { @@ -481,9 +375,7 @@ public void OnCompleted() } } - /// - /// Observer for the 7th source observable. - /// + /// Observer for the 7th source observable. /// The parent subscription. private sealed class Observer7(Subscription parent) : IObserver { diff --git a/src/ReactiveUI.Binding/Observables/CombineLatest8Observable.cs b/src/ReactiveUI.Binding/Observables/CombineLatest8Observable.cs index 328379a..0f90887 100644 --- a/src/ReactiveUI.Binding/Observables/CombineLatest8Observable.cs +++ b/src/ReactiveUI.Binding/Observables/CombineLatest8Observable.cs @@ -6,9 +6,7 @@ namespace ReactiveUI.Binding.Observables; -/// -/// Lightweight CombineLatest observable that combines the latest values from 8 source observables. -/// +/// Lightweight CombineLatest observable that combines the latest values from 8 source observables. /// The type of element 1. /// The type of element 2. /// The type of element 3. @@ -20,60 +18,36 @@ namespace ReactiveUI.Binding.Observables; /// The result element type. [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] -[SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "Deliberately large arity intrinsic to the N-argument binding/observable API surface.")] internal sealed class CombineLatest8Observable : IObservable { - /// - /// The 1st source observable sequence. - /// + /// The 1st source observable sequence. private readonly IObservable _source1; - /// - /// The 2nd source observable sequence. - /// + /// The 2nd source observable sequence. private readonly IObservable _source2; - /// - /// The 3rd source observable sequence. - /// + /// The 3rd source observable sequence. private readonly IObservable _source3; - /// - /// The 4th source observable sequence. - /// + /// The 4th source observable sequence. private readonly IObservable _source4; - /// - /// The 5th source observable sequence. - /// + /// The 5th source observable sequence. private readonly IObservable _source5; - /// - /// The 6th source observable sequence. - /// + /// The 6th source observable sequence. private readonly IObservable _source6; - /// - /// The 7th source observable sequence. - /// + /// The 7th source observable sequence. private readonly IObservable _source7; - /// - /// The 8th source observable sequence. - /// + /// The 8th source observable sequence. private readonly IObservable _source8; - /// - /// The function to combine the latest values from all sources into a result. - /// + /// The function to combine the latest values from all sources into a result. private readonly Func _resultSelector; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The 1st source observable. /// The 2nd source observable. /// The 3rd source observable. @@ -83,6 +57,7 @@ internal sealed class CombineLatest8ObservableThe 7th source observable. /// The 8th source observable. /// The function to combine the latest values. + [SuppressMessage("Design", "SST1472:Signatures should not declare too many parameters", Justification = "Parameter count is intrinsic to the fixed CombineLatest arity.")] public CombineLatest8Observable( IObservable source1, IObservable source2, @@ -131,150 +106,87 @@ public IDisposable Subscribe(IObserver observer) return sub; } - /// - /// Manages the active subscriptions to all eight source observables and emits combined results. - /// - private sealed class Subscription : IDisposable + /// Manages the active subscriptions to all eight source observables and emits combined results. + /// The downstream observer. + /// The function to combine the latest values. + private sealed class Subscription(IObserver observer, Func resultSelector) : IDisposable { - /// - /// The subscription array index for source 3. - /// + /// The subscription array index for source 3. private const int Source3Index = 2; - /// - /// The subscription array index for source 4. - /// + /// The subscription array index for source 4. private const int Source4Index = 3; - /// - /// The subscription array index for source 5. - /// + /// The subscription array index for source 5. private const int Source5Index = 4; - /// - /// The subscription array index for source 6. - /// + /// The subscription array index for source 6. private const int Source6Index = 5; - /// - /// The subscription array index for source 7. - /// + /// The subscription array index for source 7. private const int Source7Index = 6; - /// - /// The subscription array index for source 8. - /// + /// The subscription array index for source 8. private const int Source8Index = 7; - /// - /// The function to combine the latest values from all sources into a result. - /// - private readonly Func _resultSelector; + /// The function to combine the latest values from all sources into a result. + private readonly Func _resultSelector = resultSelector; - /// - /// The array of inner source subscriptions. - /// + /// The array of inner source subscriptions. private readonly IDisposable?[] _subscriptions = new IDisposable?[8]; - /// - /// The downstream observer receiving combined results. Set to on disposal. - /// - private IObserver? _observer; + /// The downstream observer receiving combined results. Set to on disposal. + private IObserver? _observer = observer; - /// - /// The latest value received from source 1. - /// + /// The latest value received from source 1. private T1 _value1 = default!; - /// - /// The latest value received from source 2. - /// + /// The latest value received from source 2. private T2 _value2 = default!; - /// - /// The latest value received from source 3. - /// + /// The latest value received from source 3. private T3 _value3 = default!; - /// - /// The latest value received from source 4. - /// + /// The latest value received from source 4. private T4 _value4 = default!; - /// - /// The latest value received from source 5. - /// + /// The latest value received from source 5. private T5 _value5 = default!; - /// - /// The latest value received from source 6. - /// + /// The latest value received from source 6. private T6 _value6 = default!; - /// - /// The latest value received from source 7. - /// + /// The latest value received from source 7. private T7 _value7 = default!; - /// - /// The latest value received from source 8. - /// + /// The latest value received from source 8. private T8 _value8 = default!; - /// - /// Whether source 1 has emitted at least one value. - /// + /// Whether source 1 has emitted at least one value. private bool _has1; - /// - /// Whether source 2 has emitted at least one value. - /// + /// Whether source 2 has emitted at least one value. private bool _has2; - /// - /// Whether source 3 has emitted at least one value. - /// + /// Whether source 3 has emitted at least one value. private bool _has3; - /// - /// Whether source 4 has emitted at least one value. - /// + /// Whether source 4 has emitted at least one value. private bool _has4; - /// - /// Whether source 5 has emitted at least one value. - /// + /// Whether source 5 has emitted at least one value. private bool _has5; - /// - /// Whether source 6 has emitted at least one value. - /// + /// Whether source 6 has emitted at least one value. private bool _has6; - /// - /// Whether source 7 has emitted at least one value. - /// + /// Whether source 7 has emitted at least one value. private bool _has7; - /// - /// Whether source 8 has emitted at least one value. - /// + /// Whether source 8 has emitted at least one value. private bool _has8; - /// - /// Initializes a new instance of the class. - /// - /// The downstream observer. - /// The function to combine the latest values. - public Subscription(IObserver observer, Func resultSelector) - { - _observer = observer; - _resultSelector = resultSelector; - } - - /// - /// Subscribes to the 1st source observable. - /// + /// Subscribes to the 1st source observable. /// The 1st source observable. public void Subscribe1(IObservable source) { @@ -282,9 +194,7 @@ public void Subscribe1(IObservable source) Volatile.Write(ref _subscriptions[0], sub); } - /// - /// Subscribes to the 2nd source observable. - /// + /// Subscribes to the 2nd source observable. /// The 2nd source observable. public void Subscribe2(IObservable source) { @@ -292,9 +202,7 @@ public void Subscribe2(IObservable source) Volatile.Write(ref _subscriptions[1], sub); } - /// - /// Subscribes to the 3rd source observable. - /// + /// Subscribes to the 3rd source observable. /// The 3rd source observable. public void Subscribe3(IObservable source) { @@ -302,9 +210,7 @@ public void Subscribe3(IObservable source) Volatile.Write(ref _subscriptions[Source3Index], sub); } - /// - /// Subscribes to the 4th source observable. - /// + /// Subscribes to the 4th source observable. /// The 4th source observable. public void Subscribe4(IObservable source) { @@ -312,9 +218,7 @@ public void Subscribe4(IObservable source) Volatile.Write(ref _subscriptions[Source4Index], sub); } - /// - /// Subscribes to the 5th source observable. - /// + /// Subscribes to the 5th source observable. /// The 5th source observable. public void Subscribe5(IObservable source) { @@ -322,9 +226,7 @@ public void Subscribe5(IObservable source) Volatile.Write(ref _subscriptions[Source5Index], sub); } - /// - /// Subscribes to the 6th source observable. - /// + /// Subscribes to the 6th source observable. /// The 6th source observable. public void Subscribe6(IObservable source) { @@ -332,9 +234,7 @@ public void Subscribe6(IObservable source) Volatile.Write(ref _subscriptions[Source6Index], sub); } - /// - /// Subscribes to the 7th source observable. - /// + /// Subscribes to the 7th source observable. /// The 7th source observable. public void Subscribe7(IObservable source) { @@ -342,9 +242,7 @@ public void Subscribe7(IObservable source) Volatile.Write(ref _subscriptions[Source7Index], sub); } - /// - /// Subscribes to the 8th source observable. - /// + /// Subscribes to the 8th source observable. /// The 8th source observable. public void Subscribe8(IObservable source) { @@ -355,7 +253,7 @@ public void Subscribe8(IObservable source) /// public void Dispose() { - if (Interlocked.Exchange(ref _observer, null) == null) + if (Interlocked.Exchange(ref _observer, null) is null) { return; } @@ -366,9 +264,7 @@ public void Dispose() } } - /// - /// Emits the combined result if all sources have produced at least one value. - /// + /// Emits the combined result if all sources have produced at least one value. private void TryEmit() { if (!_has1 || !_has2 || !_has3 || !_has4 || !_has5 || !_has6 || !_has7 || !_has8) @@ -376,12 +272,10 @@ private void TryEmit() return; } - _observer?.OnNext(_resultSelector(_value1, _value2, _value3, _value4, _value5, _value6, _value7, _value8)); + Volatile.Read(ref _observer)?.OnNext(_resultSelector(_value1, _value2, _value3, _value4, _value5, _value6, _value7, _value8)); } - /// - /// Observer for the 1st source observable. - /// + /// Observer for the 1st source observable. /// The parent subscription. private sealed class Observer1(Subscription parent) : IObserver { @@ -402,9 +296,7 @@ public void OnCompleted() } } - /// - /// Observer for the 2nd source observable. - /// + /// Observer for the 2nd source observable. /// The parent subscription. private sealed class Observer2(Subscription parent) : IObserver { @@ -425,9 +317,7 @@ public void OnCompleted() } } - /// - /// Observer for the 3rd source observable. - /// + /// Observer for the 3rd source observable. /// The parent subscription. private sealed class Observer3(Subscription parent) : IObserver { @@ -448,9 +338,7 @@ public void OnCompleted() } } - /// - /// Observer for the 4th source observable. - /// + /// Observer for the 4th source observable. /// The parent subscription. private sealed class Observer4(Subscription parent) : IObserver { @@ -471,9 +359,7 @@ public void OnCompleted() } } - /// - /// Observer for the 5th source observable. - /// + /// Observer for the 5th source observable. /// The parent subscription. private sealed class Observer5(Subscription parent) : IObserver { @@ -494,9 +380,7 @@ public void OnCompleted() } } - /// - /// Observer for the 6th source observable. - /// + /// Observer for the 6th source observable. /// The parent subscription. private sealed class Observer6(Subscription parent) : IObserver { @@ -517,9 +401,7 @@ public void OnCompleted() } } - /// - /// Observer for the 7th source observable. - /// + /// Observer for the 7th source observable. /// The parent subscription. private sealed class Observer7(Subscription parent) : IObserver { @@ -540,9 +422,7 @@ public void OnCompleted() } } - /// - /// Observer for the 8th source observable. - /// + /// Observer for the 8th source observable. /// The parent subscription. private sealed class Observer8(Subscription parent) : IObserver { diff --git a/src/ReactiveUI.Binding/Observables/CombineLatest9Observable.cs b/src/ReactiveUI.Binding/Observables/CombineLatest9Observable.cs index 8ea76d4..1692dc9 100644 --- a/src/ReactiveUI.Binding/Observables/CombineLatest9Observable.cs +++ b/src/ReactiveUI.Binding/Observables/CombineLatest9Observable.cs @@ -6,9 +6,7 @@ namespace ReactiveUI.Binding.Observables; -/// -/// Lightweight CombineLatest observable that combines the latest values from 9 source observables. -/// +/// Lightweight CombineLatest observable that combines the latest values from 9 source observables. /// The type of element 1. /// The type of element 2. /// The type of element 3. @@ -21,65 +19,39 @@ namespace ReactiveUI.Binding.Observables; /// The result element type. [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] -[SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "Deliberately large arity intrinsic to the N-argument binding/observable API surface.")] internal sealed class CombineLatest9Observable : IObservable { - /// - /// The 1st source observable sequence. - /// + /// The 1st source observable sequence. private readonly IObservable _source1; - /// - /// The 2nd source observable sequence. - /// + /// The 2nd source observable sequence. private readonly IObservable _source2; - /// - /// The 3rd source observable sequence. - /// + /// The 3rd source observable sequence. private readonly IObservable _source3; - /// - /// The 4th source observable sequence. - /// + /// The 4th source observable sequence. private readonly IObservable _source4; - /// - /// The 5th source observable sequence. - /// + /// The 5th source observable sequence. private readonly IObservable _source5; - /// - /// The 6th source observable sequence. - /// + /// The 6th source observable sequence. private readonly IObservable _source6; - /// - /// The 7th source observable sequence. - /// + /// The 7th source observable sequence. private readonly IObservable _source7; - /// - /// The 8th source observable sequence. - /// + /// The 8th source observable sequence. private readonly IObservable _source8; - /// - /// The 9th source observable sequence. - /// + /// The 9th source observable sequence. private readonly IObservable _source9; - /// - /// The function to combine the latest values from all sources into a result. - /// + /// The function to combine the latest values from all sources into a result. private readonly Func _resultSelector; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The 1st source observable. /// The 2nd source observable. /// The 3rd source observable. @@ -90,6 +62,7 @@ internal sealed class CombineLatest9ObservableThe 8th source observable. /// The 9th source observable. /// The function to combine the latest values. + [SuppressMessage("Design", "SST1472:Signatures should not declare too many parameters", Justification = "Parameter count is intrinsic to the fixed CombineLatest arity.")] public CombineLatest9Observable( IObservable source1, IObservable source2, @@ -142,127 +115,74 @@ public IDisposable Subscribe(IObserver observer) return sub; } - /// - /// Manages the active subscriptions to all nine source observables and emits combined results. - /// - private sealed class Subscription : IDisposable + /// Manages the active subscriptions to all nine source observables and emits combined results. + /// The downstream observer. + /// The function to combine the latest values. + private sealed class Subscription( + IObserver observer, + Func resultSelector) : IDisposable { - /// - /// The subscription array index for source 3. - /// + /// The subscription array index for source 3. private const int Source3Index = 2; - /// - /// The subscription array index for source 4. - /// + /// The subscription array index for source 4. private const int Source4Index = 3; - /// - /// The subscription array index for source 5. - /// + /// The subscription array index for source 5. private const int Source5Index = 4; - /// - /// The subscription array index for source 6. - /// + /// The subscription array index for source 6. private const int Source6Index = 5; - /// - /// The subscription array index for source 7. - /// + /// The subscription array index for source 7. private const int Source7Index = 6; - /// - /// The subscription array index for source 8. - /// + /// The subscription array index for source 8. private const int Source8Index = 7; - /// - /// The subscription array index for source 9. - /// + /// The subscription array index for source 9. private const int Source9Index = 8; - /// - /// The function to combine the latest values from all sources into a result. - /// - private readonly Func _resultSelector; + /// The function to combine the latest values from all sources into a result. + private readonly Func _resultSelector = resultSelector; - /// - /// The array of inner source subscriptions. - /// + /// The array of inner source subscriptions. private readonly IDisposable?[] _subscriptions = new IDisposable?[9]; - /// - /// The downstream observer receiving combined results. Set to on disposal. - /// - private IObserver? _observer; + /// The downstream observer receiving combined results. Set to on disposal. + private IObserver? _observer = observer; - /// - /// The latest value received from source 1. - /// + /// The latest value received from source 1. private T1 _value1 = default!; - /// - /// The latest value received from source 2. - /// + /// The latest value received from source 2. private T2 _value2 = default!; - /// - /// The latest value received from source 3. - /// + /// The latest value received from source 3. private T3 _value3 = default!; - /// - /// The latest value received from source 4. - /// + /// The latest value received from source 4. private T4 _value4 = default!; - /// - /// The latest value received from source 5. - /// + /// The latest value received from source 5. private T5 _value5 = default!; - /// - /// The latest value received from source 6. - /// + /// The latest value received from source 6. private T6 _value6 = default!; - /// - /// The latest value received from source 7. - /// + /// The latest value received from source 7. private T7 _value7 = default!; - /// - /// The latest value received from source 8. - /// + /// The latest value received from source 8. private T8 _value8 = default!; - /// - /// The latest value received from source 9. - /// + /// The latest value received from source 9. private T9 _value9 = default!; - /// - /// Bitmask of the sources that have emitted at least one value; compared against the all-ready mask. - /// + /// Bitmask of the sources that have emitted at least one value; compared against the all-ready mask. private int _readyMask; - /// - /// Initializes a new instance of the class. - /// - /// The downstream observer. - /// The function to combine the latest values. - public Subscription( - IObserver observer, - Func resultSelector) - { - _observer = observer; - _resultSelector = resultSelector; - } - - /// - /// Subscribes to the 1st source observable. - /// + /// Subscribes to the 1st source observable. /// The 1st source observable. public void Subscribe1(IObservable source) { @@ -270,9 +190,7 @@ public void Subscribe1(IObservable source) Volatile.Write(ref _subscriptions[0], sub); } - /// - /// Subscribes to the 2nd source observable. - /// + /// Subscribes to the 2nd source observable. /// The 2nd source observable. public void Subscribe2(IObservable source) { @@ -280,9 +198,7 @@ public void Subscribe2(IObservable source) Volatile.Write(ref _subscriptions[1], sub); } - /// - /// Subscribes to the 3rd source observable. - /// + /// Subscribes to the 3rd source observable. /// The 3rd source observable. public void Subscribe3(IObservable source) { @@ -290,9 +206,7 @@ public void Subscribe3(IObservable source) Volatile.Write(ref _subscriptions[Source3Index], sub); } - /// - /// Subscribes to the 4th source observable. - /// + /// Subscribes to the 4th source observable. /// The 4th source observable. public void Subscribe4(IObservable source) { @@ -300,9 +214,7 @@ public void Subscribe4(IObservable source) Volatile.Write(ref _subscriptions[Source4Index], sub); } - /// - /// Subscribes to the 5th source observable. - /// + /// Subscribes to the 5th source observable. /// The 5th source observable. public void Subscribe5(IObservable source) { @@ -310,9 +222,7 @@ public void Subscribe5(IObservable source) Volatile.Write(ref _subscriptions[Source5Index], sub); } - /// - /// Subscribes to the 6th source observable. - /// + /// Subscribes to the 6th source observable. /// The 6th source observable. public void Subscribe6(IObservable source) { @@ -320,9 +230,7 @@ public void Subscribe6(IObservable source) Volatile.Write(ref _subscriptions[Source6Index], sub); } - /// - /// Subscribes to the 7th source observable. - /// + /// Subscribes to the 7th source observable. /// The 7th source observable. public void Subscribe7(IObservable source) { @@ -330,9 +238,7 @@ public void Subscribe7(IObservable source) Volatile.Write(ref _subscriptions[Source7Index], sub); } - /// - /// Subscribes to the 8th source observable. - /// + /// Subscribes to the 8th source observable. /// The 8th source observable. public void Subscribe8(IObservable source) { @@ -340,9 +246,7 @@ public void Subscribe8(IObservable source) Volatile.Write(ref _subscriptions[Source8Index], sub); } - /// - /// Subscribes to the 9th source observable. - /// + /// Subscribes to the 9th source observable. /// The 9th source observable. public void Subscribe9(IObservable source) { @@ -353,7 +257,7 @@ public void Subscribe9(IObservable source) /// public void Dispose() { - if (Interlocked.Exchange(ref _observer, null) == null) + if (Interlocked.Exchange(ref _observer, null) is null) { return; } @@ -364,9 +268,7 @@ public void Dispose() } } - /// - /// Emits the combined result if all sources have produced at least one value. - /// + /// Emits the combined result if all sources have produced at least one value. private void TryEmit() { if (_readyMask != (1 << _subscriptions.Length) - 1) @@ -374,12 +276,10 @@ private void TryEmit() return; } - _observer?.OnNext(_resultSelector(_value1, _value2, _value3, _value4, _value5, _value6, _value7, _value8, _value9)); + Volatile.Read(ref _observer)?.OnNext(_resultSelector(_value1, _value2, _value3, _value4, _value5, _value6, _value7, _value8, _value9)); } - /// - /// Observer for the 1st source observable. - /// + /// Observer for the 1st source observable. /// The parent subscription. private sealed class Observer1(Subscription parent) : IObserver { @@ -400,9 +300,7 @@ public void OnCompleted() } } - /// - /// Observer for the 2nd source observable. - /// + /// Observer for the 2nd source observable. /// The parent subscription. private sealed class Observer2(Subscription parent) : IObserver { @@ -423,9 +321,7 @@ public void OnCompleted() } } - /// - /// Observer for the 3rd source observable. - /// + /// Observer for the 3rd source observable. /// The parent subscription. private sealed class Observer3(Subscription parent) : IObserver { @@ -446,9 +342,7 @@ public void OnCompleted() } } - /// - /// Observer for the 4th source observable. - /// + /// Observer for the 4th source observable. /// The parent subscription. private sealed class Observer4(Subscription parent) : IObserver { @@ -469,9 +363,7 @@ public void OnCompleted() } } - /// - /// Observer for the 5th source observable. - /// + /// Observer for the 5th source observable. /// The parent subscription. private sealed class Observer5(Subscription parent) : IObserver { @@ -492,9 +384,7 @@ public void OnCompleted() } } - /// - /// Observer for the 6th source observable. - /// + /// Observer for the 6th source observable. /// The parent subscription. private sealed class Observer6(Subscription parent) : IObserver { @@ -515,9 +405,7 @@ public void OnCompleted() } } - /// - /// Observer for the 7th source observable. - /// + /// Observer for the 7th source observable. /// The parent subscription. private sealed class Observer7(Subscription parent) : IObserver { @@ -538,9 +426,7 @@ public void OnCompleted() } } - /// - /// Observer for the 8th source observable. - /// + /// Observer for the 8th source observable. /// The parent subscription. private sealed class Observer8(Subscription parent) : IObserver { @@ -561,9 +447,7 @@ public void OnCompleted() } } - /// - /// Observer for the 9th source observable. - /// + /// Observer for the 9th source observable. /// The parent subscription. private sealed class Observer9(Subscription parent) : IObserver { diff --git a/src/ReactiveUI.Binding/Observables/CombineLatestObservable.cs b/src/ReactiveUI.Binding/Observables/CombineLatestObservable.cs index 0ca5f77..255af34 100644 --- a/src/ReactiveUI.Binding/Observables/CombineLatestObservable.cs +++ b/src/ReactiveUI.Binding/Observables/CombineLatestObservable.cs @@ -12,15 +12,9 @@ namespace ReactiveUI.Binding.Observables; /// [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] -[SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "Deliberately large arity intrinsic to the N-argument binding/observable API surface.")] public static class CombineLatestObservable { - /// - /// Combines the latest values from two observables using a result selector. - /// + /// Combines the latest values from two observables using a result selector. /// Source element type 1. /// Source element type 2. /// The result element type. @@ -34,9 +28,7 @@ public static IObservable Create( Func resultSelector) => new CombineLatest2Observable(source1, source2, resultSelector); - /// - /// Combines the latest values from three observables using a result selector. - /// + /// Combines the latest values from three observables using a result selector. /// Source element type 1. /// Source element type 2. /// Source element type 3. @@ -53,9 +45,7 @@ public static IObservable Create( Func resultSelector) => new CombineLatest3Observable(source1, source2, source3, resultSelector); - /// - /// Combines the latest values from four observables using a result selector. - /// + /// Combines the latest values from four observables using a result selector. /// Source element type 1. /// Source element type 2. /// Source element type 3. @@ -75,9 +65,7 @@ public static IObservable Create( Func resultSelector) => new CombineLatest4Observable(source1, source2, source3, source4, resultSelector); - /// - /// Combines the latest values from five observables using a result selector. - /// + /// Combines the latest values from five observables using a result selector. /// Source element type 1. /// Source element type 2. /// Source element type 3. @@ -106,9 +94,7 @@ public static IObservable Create( source5, resultSelector); - /// - /// Combines the latest values from six observables using a result selector. - /// + /// Combines the latest values from six observables using a result selector. /// Source element type 1. /// Source element type 2. /// Source element type 3. @@ -141,9 +127,7 @@ public static IObservable Create( source6, resultSelector); - /// - /// Combines the latest values from seven observables using a result selector. - /// + /// Combines the latest values from seven observables using a result selector. /// Source element type 1. /// Source element type 2. /// Source element type 3. @@ -161,6 +145,7 @@ public static IObservable Create( /// Source observable 7. /// The function to combine the latest values. /// An observable of combined results. + [SuppressMessage("Design", "SST1472:Signatures should not declare too many parameters", Justification = "Parameter count is intrinsic to the fixed CombineLatest arity.")] public static IObservable Create( IObservable source1, IObservable source2, @@ -180,9 +165,7 @@ public static IObservable Create( source7, resultSelector); - /// - /// Combines the latest values from eight observables using a result selector. - /// + /// Combines the latest values from eight observables using a result selector. /// Source element type 1. /// Source element type 2. /// Source element type 3. @@ -202,6 +185,7 @@ public static IObservable Create( /// Source observable 8. /// The function to combine the latest values. /// An observable of combined results. + [SuppressMessage("Design", "SST1472:Signatures should not declare too many parameters", Justification = "Parameter count is intrinsic to the fixed CombineLatest arity.")] public static IObservable Create( IObservable source1, IObservable source2, @@ -223,9 +207,7 @@ public static IObservable Create - /// Combines the latest values from nine observables using a result selector. - /// + /// Combines the latest values from nine observables using a result selector. /// Source element type 1. /// Source element type 2. /// Source element type 3. @@ -247,6 +229,7 @@ public static IObservable CreateSource observable 9. /// The function to combine the latest values. /// An observable of combined results. + [SuppressMessage("Design", "SST1472:Signatures should not declare too many parameters", Justification = "Parameter count is intrinsic to the fixed CombineLatest arity.")] public static IObservable Create( IObservable source1, IObservable source2, @@ -270,9 +253,7 @@ public static IObservable Create - /// Combines the latest values from ten observables using a result selector. - /// + /// Combines the latest values from ten observables using a result selector. /// Source element type 1. /// Source element type 2. /// Source element type 3. @@ -296,6 +277,7 @@ public static IObservable CreateSource observable 10. /// The function to combine the latest values. /// An observable of combined results. + [SuppressMessage("Design", "SST1472:Signatures should not declare too many parameters", Justification = "Parameter count is intrinsic to the fixed CombineLatest arity.")] public static IObservable Create( IObservable source1, IObservable source2, @@ -321,9 +303,7 @@ public static IObservable Create - /// Combines the latest values from eleven observables using a result selector. - /// + /// Combines the latest values from eleven observables using a result selector. /// Source element type 1. /// Source element type 2. /// Source element type 3. @@ -349,6 +329,7 @@ public static IObservable CreateSource observable 11. /// The function to combine the latest values. /// An observable of combined results. + [SuppressMessage("Design", "SST1472:Signatures should not declare too many parameters", Justification = "Parameter count is intrinsic to the fixed CombineLatest arity.")] public static IObservable Create( IObservable source1, IObservable source2, @@ -376,9 +357,7 @@ public static IObservable Create - /// Combines the latest values from twelve observables using a result selector. - /// + /// Combines the latest values from twelve observables using a result selector. /// Source element type 1. /// Source element type 2. /// Source element type 3. @@ -406,6 +385,7 @@ public static IObservable CreateSource observable 12. /// The function to combine the latest values. /// An observable of combined results. + [SuppressMessage("Design", "SST1472:Signatures should not declare too many parameters", Justification = "Parameter count is intrinsic to the fixed CombineLatest arity.")] public static IObservable Create( IObservable source1, IObservable source2, @@ -435,9 +415,7 @@ public static IObservable Create - /// Combines the latest values from thirteen observables using a result selector. - /// + /// Combines the latest values from thirteen observables using a result selector. /// Source element type 1. /// Source element type 2. /// Source element type 3. @@ -467,6 +445,7 @@ public static IObservable CreateSource observable 13. /// The function to combine the latest values. /// An observable of combined results. + [SuppressMessage("Design", "SST1472:Signatures should not declare too many parameters", Justification = "Parameter count is intrinsic to the fixed CombineLatest arity.")] public static IObservable Create( IObservable source1, IObservable source2, @@ -498,9 +477,7 @@ public static IObservable Create - /// Combines the latest values from fourteen observables using a result selector. - /// + /// Combines the latest values from fourteen observables using a result selector. /// Source element type 1. /// Source element type 2. /// Source element type 3. @@ -532,6 +509,7 @@ public static IObservable CreateSource observable 14. /// The function to combine the latest values. /// An observable of combined results. + [SuppressMessage("Design", "SST1472:Signatures should not declare too many parameters", Justification = "Parameter count is intrinsic to the fixed CombineLatest arity.")] public static IObservable Create( IObservable source1, IObservable source2, @@ -565,9 +543,7 @@ public static IObservable Create - /// Combines the latest values from fifteen observables using a result selector. - /// + /// Combines the latest values from fifteen observables using a result selector. /// Source element type 1. /// Source element type 2. /// Source element type 3. @@ -601,6 +577,7 @@ public static IObservable CreateSource observable 15. /// The function to combine the latest values. /// An observable of combined results. + [SuppressMessage("Design", "SST1472:Signatures should not declare too many parameters", Justification = "Parameter count is intrinsic to the fixed CombineLatest arity.")] public static IObservable Create< T1, T2, @@ -652,9 +629,7 @@ public static IObservable Create< source15, resultSelector); - /// - /// Combines the latest values from sixteen observables using a result selector. - /// + /// Combines the latest values from sixteen observables using a result selector. /// Source element type 1. /// Source element type 2. /// Source element type 3. @@ -690,6 +665,7 @@ public static IObservable Create< /// Source observable 16. /// The function to combine the latest values. /// An observable of combined results. + [SuppressMessage("Design", "SST1472:Signatures should not declare too many parameters", Justification = "Parameter count is intrinsic to the fixed CombineLatest arity.")] public static IObservable Create< T1, T2, diff --git a/src/ReactiveUI.Binding/Observables/CompositeDisposable2.cs b/src/ReactiveUI.Binding/Observables/CompositeDisposable2.cs index c4a2a14..852da17 100644 --- a/src/ReactiveUI.Binding/Observables/CompositeDisposable2.cs +++ b/src/ReactiveUI.Binding/Observables/CompositeDisposable2.cs @@ -13,24 +13,16 @@ namespace ReactiveUI.Binding.Observables; [EditorBrowsable(EditorBrowsableState.Never)] public sealed class CompositeDisposable2 : IDisposable { - /// - /// The first disposable resource. - /// + /// The first disposable resource. private readonly IDisposable _d1; - /// - /// The second disposable resource. - /// + /// The second disposable resource. private readonly IDisposable _d2; - /// - /// Guard flag to ensure disposal occurs exactly once (0 = not disposed, 1 = disposed). - /// + /// Guard flag to ensure disposal occurs exactly once (0 = not disposed, 1 = disposed). private int _disposed; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The first disposable. /// The second disposable. public CompositeDisposable2(IDisposable d1, IDisposable d2) @@ -53,9 +45,7 @@ public void Dispose() _d2.Dispose(); } - /// - /// Atomically marks this instance as disposed. - /// + /// Atomically marks this instance as disposed. /// if this is the first disposal; otherwise . [ExcludeFromCodeCoverage] [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ReactiveUI.Binding/Observables/DistinctUntilChangedByObservable.cs b/src/ReactiveUI.Binding/Observables/DistinctUntilChangedByObservable.cs index 58538a2..e822695 100644 --- a/src/ReactiveUI.Binding/Observables/DistinctUntilChangedByObservable.cs +++ b/src/ReactiveUI.Binding/Observables/DistinctUntilChangedByObservable.cs @@ -15,24 +15,16 @@ namespace ReactiveUI.Binding.Observables; [EditorBrowsable(EditorBrowsableState.Never)] public sealed class DistinctUntilChangedByObservable : IObservable { - /// - /// The upstream source observable. - /// + /// The upstream source observable. private readonly IObservable _source; - /// - /// The key selector used to derive the comparison key from each value. - /// + /// The key selector used to derive the comparison key from each value. private readonly Func _keySelector; - /// - /// The equality comparer used to detect duplicate consecutive keys. - /// + /// The equality comparer used to detect duplicate consecutive keys. private readonly IEqualityComparer _comparer; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The source observable. /// The key selector used to derive the comparison key from each value. public DistinctUntilChangedByObservable(IObservable source, Func keySelector) @@ -52,49 +44,27 @@ public IDisposable Subscribe(IObserver observer) return _source.Subscribe(new DistinctObserver(observer, _keySelector, _comparer)); } - /// - /// Observer that suppresses consecutive values whose projected keys are equal. - /// - private sealed class DistinctObserver : IObserver + /// Observer that suppresses consecutive values whose projected keys are equal. + /// The downstream observer. + /// The key selector. + /// The equality comparer. + private sealed class DistinctObserver(IObserver observer, Func keySelector, IEqualityComparer comparer) : IObserver { - /// - /// The downstream observer. - /// - private readonly IObserver _observer; - - /// - /// The key selector used to derive the comparison key from each value. - /// - private readonly Func _keySelector; - - /// - /// The equality comparer used to detect duplicate consecutive keys. - /// - private readonly IEqualityComparer _comparer; - - /// - /// The key of the most recently emitted value. - /// + /// The downstream observer. + private readonly IObserver _observer = observer; + + /// The key selector used to derive the comparison key from each value. + private readonly Func _keySelector = keySelector; + + /// The equality comparer used to detect duplicate consecutive keys. + private readonly IEqualityComparer _comparer = comparer; + + /// The key of the most recently emitted value. private TKey _lastKey = default!; - /// - /// Whether at least one value has been emitted. - /// + /// Whether at least one value has been emitted. private bool _hasValue; - /// - /// Initializes a new instance of the class. - /// - /// The downstream observer. - /// The key selector. - /// The equality comparer. - public DistinctObserver(IObserver observer, Func keySelector, IEqualityComparer comparer) - { - _observer = observer; - _keySelector = keySelector; - _comparer = comparer; - } - /// public void OnNext(TSource value) { diff --git a/src/ReactiveUI.Binding/Observables/DistinctUntilChangedObservable.cs b/src/ReactiveUI.Binding/Observables/DistinctUntilChangedObservable.cs index 3e446ed..6474c17 100644 --- a/src/ReactiveUI.Binding/Observables/DistinctUntilChangedObservable.cs +++ b/src/ReactiveUI.Binding/Observables/DistinctUntilChangedObservable.cs @@ -14,28 +14,20 @@ namespace ReactiveUI.Binding.Observables; [EditorBrowsable(EditorBrowsableState.Never)] public sealed class DistinctUntilChangedObservable : IObservable { - /// - /// The upstream source observable. - /// + /// The upstream source observable. private readonly IObservable _source; - /// - /// The equality comparer used to detect duplicate consecutive values. - /// + /// The equality comparer used to detect duplicate consecutive values. private readonly IEqualityComparer _comparer; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The source observable. public DistinctUntilChangedObservable(IObservable source) : this(source, EqualityComparer.Default) { } - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The source observable. /// The equality comparer to use. public DistinctUntilChangedObservable(IObservable source, IEqualityComparer comparer) @@ -54,42 +46,23 @@ public IDisposable Subscribe(IObserver observer) return _source.Subscribe(new DistinctObserver(observer, _comparer)); } - /// - /// Observer that suppresses consecutive duplicate values. - /// - private sealed class DistinctObserver : IObserver + /// Observer that suppresses consecutive duplicate values. + /// The downstream observer. + /// The equality comparer. + private sealed class DistinctObserver(IObserver observer, IEqualityComparer comparer) : IObserver { - /// - /// The downstream observer. - /// - private readonly IObserver _observer; - - /// - /// The equality comparer used to detect duplicates. - /// - private readonly IEqualityComparer _comparer; - - /// - /// The most recently emitted value. - /// + /// The downstream observer. + private readonly IObserver _observer = observer; + + /// The equality comparer used to detect duplicates. + private readonly IEqualityComparer _comparer = comparer; + + /// The most recently emitted value. private T _lastValue = default!; - /// - /// Whether at least one value has been emitted. - /// + /// Whether at least one value has been emitted. private bool _hasValue; - /// - /// Initializes a new instance of the class. - /// - /// The downstream observer. - /// The equality comparer. - public DistinctObserver(IObserver observer, IEqualityComparer comparer) - { - _observer = observer; - _comparer = comparer; - } - /// public void OnNext(T value) { diff --git a/src/ReactiveUI.Binding/Observables/EmptyDisposable.cs b/src/ReactiveUI.Binding/Observables/EmptyDisposable.cs index e05433d..1074d4d 100644 --- a/src/ReactiveUI.Binding/Observables/EmptyDisposable.cs +++ b/src/ReactiveUI.Binding/Observables/EmptyDisposable.cs @@ -13,15 +13,10 @@ namespace ReactiveUI.Binding.Observables; [EditorBrowsable(EditorBrowsableState.Never)] public sealed class EmptyDisposable : IDisposable { - /// - /// Gets the singleton instance. - /// + /// Gets the singleton instance. public static readonly EmptyDisposable Instance = new(); - /// - /// Initializes a new instance of the class. - /// Prevents external instantiation. Use instead. - /// + /// Initializes a new instance of the class. Prevents external instantiation. Use instead. private EmptyDisposable() { } diff --git a/src/ReactiveUI.Binding/Observables/EmptyObservable.cs b/src/ReactiveUI.Binding/Observables/EmptyObservable.cs index 9c0a0bb..3815d7f 100644 --- a/src/ReactiveUI.Binding/Observables/EmptyObservable.cs +++ b/src/ReactiveUI.Binding/Observables/EmptyObservable.cs @@ -14,15 +14,10 @@ namespace ReactiveUI.Binding.Observables; [EditorBrowsable(EditorBrowsableState.Never)] public sealed class EmptyObservable : IObservable { - /// - /// Gets the singleton instance for this element type. - /// + /// Gets the singleton instance for this element type. public static readonly EmptyObservable Instance = new(); - /// - /// Initializes a new instance of the class. - /// Prevents external instantiation. Use instead. - /// + /// Initializes a new instance of the class. Prevents external instantiation. Use instead. private EmptyObservable() { } diff --git a/src/ReactiveUI.Binding/Observables/EventObservable.cs b/src/ReactiveUI.Binding/Observables/EventObservable.cs index de75ee3..0efdc73 100644 --- a/src/ReactiveUI.Binding/Observables/EventObservable.cs +++ b/src/ReactiveUI.Binding/Observables/EventObservable.cs @@ -17,29 +17,19 @@ namespace ReactiveUI.Binding.Observables; [EditorBrowsable(EditorBrowsableState.Never)] public sealed class EventObservable : IObservable { - /// - /// Delegate that subscribes the handler to the event source. - /// + /// Delegate that subscribes the handler to the event source. private readonly Action _addHandler; - /// - /// Delegate that unsubscribes the handler from the event source. - /// + /// Delegate that unsubscribes the handler from the event source. private readonly Action _removeHandler; - /// - /// Delegate that reads the current property value from the source. - /// + /// Delegate that reads the current property value from the source. private readonly Func _getter; - /// - /// Whether to suppress duplicate consecutive values. - /// + /// Whether to suppress duplicate consecutive values. private readonly bool _distinctUntilChanged; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// A delegate that subscribes an to the property change event. /// A delegate that unsubscribes an from the property change event. /// A delegate that reads the current property value. @@ -67,40 +57,25 @@ public IDisposable Subscribe(IObserver observer) return new Subscription(this, observer); } - /// - /// Manages the event subscription for a single observer, with optional distinct-until-changed filtering. - /// + /// Manages the event subscription for a single observer, with optional distinct-until-changed filtering. private sealed class Subscription : IDisposable { - /// - /// The parent observable that owns the add/remove handlers and getter. - /// + /// The parent observable that owns the add/remove handlers and getter. private readonly EventObservable _parent; - /// - /// The equality comparer used for distinct-until-changed filtering. - /// + /// The equality comparer used for distinct-until-changed filtering. private readonly EqualityComparer _comparer; - /// - /// The downstream observer. Set to on disposal. - /// + /// The downstream observer. Set to on disposal. private IObserver? _observer; - /// - /// The most recently emitted value, used for distinct-until-changed comparison. - /// + /// The most recently emitted value, used for distinct-until-changed comparison. private T _lastValue; - /// - /// Whether at least one value has been emitted. - /// + /// Whether at least one value has been emitted. private bool _hasValue; - /// - /// Initializes a new instance of the class. - /// Subscribes to the event source and emits the initial property value. - /// + /// Initializes a new instance of the class. Subscribes to the event source and emits the initial property value. /// The parent observable. /// The downstream observer. public Subscription(EventObservable parent, IObserver observer) @@ -129,13 +104,11 @@ public void Dispose() _parent._removeHandler(OnValueChanged); } - /// - /// Atomically nulls the observer, returning whether it was previously non-null. - /// + /// Atomically nulls the observer, returning whether it was previously non-null. /// if this is the first disposal; otherwise . [ExcludeFromCodeCoverage] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal bool TrySetDisposed() => Interlocked.Exchange(ref _observer, null) != null; + private bool TrySetDisposed() => Interlocked.Exchange(ref _observer, null) is not null; /// /// Handles the event and forwards the current property value to the observer diff --git a/src/ReactiveUI.Binding/Observables/MergeObservable.cs b/src/ReactiveUI.Binding/Observables/MergeObservable.cs index b4ea995..452e4f3 100644 --- a/src/ReactiveUI.Binding/Observables/MergeObservable.cs +++ b/src/ReactiveUI.Binding/Observables/MergeObservable.cs @@ -14,14 +14,10 @@ namespace ReactiveUI.Binding.Observables; [EditorBrowsable(EditorBrowsableState.Never)] public sealed class MergeObservable : IObservable { - /// - /// The array of source observables to merge. - /// + /// The array of source observables to merge. private readonly IObservable[] _sources; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The source observables to merge. public MergeObservable(params IObservable[] sources) { @@ -45,19 +41,13 @@ public IDisposable Subscribe(IObserver observer) return new MergeSubscription(subscriptions); } - /// - /// Observer that forwards all values from any source to the downstream observer. - /// + /// Observer that forwards all values from any source to the downstream observer. private sealed class MergeObserver : IObserver { - /// - /// The downstream observer. - /// + /// The downstream observer. private readonly IObserver _observer; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The downstream observer. public MergeObserver(IObserver observer) => _observer = observer; @@ -76,19 +66,13 @@ public void OnCompleted() } } - /// - /// Manages the lifetime of all source subscriptions. - /// + /// Manages the lifetime of all source subscriptions. private sealed class MergeSubscription : IDisposable { - /// - /// The array of source subscriptions. Set to on disposal. - /// + /// The array of source subscriptions. Set to on disposal. private IDisposable[]? _subscriptions; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The source subscriptions to manage. public MergeSubscription(IDisposable[] subscriptions) => _subscriptions = subscriptions; @@ -107,12 +91,10 @@ public void Dispose() } } - /// - /// Atomically takes the subscriptions array, returning it exactly once. - /// + /// Atomically takes the subscriptions array, returning it exactly once. /// The subscriptions if this is the first call; otherwise . [ExcludeFromCodeCoverage] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal IDisposable[]? TryTakeSubscriptions() => Interlocked.Exchange(ref _subscriptions, null); + private IDisposable[]? TryTakeSubscriptions() => Interlocked.Exchange(ref _subscriptions, null); } } diff --git a/src/ReactiveUI.Binding/Observables/NeverObservable.cs b/src/ReactiveUI.Binding/Observables/NeverObservable.cs index 3d5aee6..de6031d 100644 --- a/src/ReactiveUI.Binding/Observables/NeverObservable.cs +++ b/src/ReactiveUI.Binding/Observables/NeverObservable.cs @@ -14,15 +14,10 @@ namespace ReactiveUI.Binding.Observables; [EditorBrowsable(EditorBrowsableState.Never)] public sealed class NeverObservable : IObservable { - /// - /// Gets the singleton instance for this element type. - /// + /// Gets the singleton instance for this element type. public static readonly NeverObservable Instance = new(); - /// - /// Initializes a new instance of the class. - /// Prevents external instantiation. Use instead. - /// + /// Initializes a new instance of the class. Prevents external instantiation. Use instead. private NeverObservable() { } diff --git a/src/ReactiveUI.Binding/Observables/NotifyPropertyChangedObservable.cs b/src/ReactiveUI.Binding/Observables/NotifyPropertyChangedObservable.cs index 20b9be8..d97cf09 100644 --- a/src/ReactiveUI.Binding/Observables/NotifyPropertyChangedObservable.cs +++ b/src/ReactiveUI.Binding/Observables/NotifyPropertyChangedObservable.cs @@ -16,29 +16,19 @@ namespace ReactiveUI.Binding.Observables; [EditorBrowsable(EditorBrowsableState.Never)] public sealed class NotifyPropertyChangedObservable : IObservable> { - /// - /// The source object raising the notifications. - /// + /// The source object raising the notifications. private readonly object _sender; - /// - /// The expression surfaced on the emitted observed change. - /// + /// The expression surfaced on the emitted observed change. private readonly Expression _expression; - /// - /// The observed property name (with the [] suffix already applied for indexers). - /// - private readonly string _expectedName; + /// The observed property name (with the [] suffix already applied for indexers). + private readonly string _observedPropertyName; - /// - /// Whether to observe before-change () notifications. - /// + /// Whether to observe before-change () notifications. private readonly bool _beforeChanged; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The source object raising the notifications. /// The expression surfaced on the emitted observed change. /// The observed property name (with the [] suffix already applied for indexers). @@ -50,7 +40,7 @@ public NotifyPropertyChangedObservable(object sender, Expression expression, str ArgumentExceptionHelper.ThrowIfNull(expectedName); _sender = sender; _expression = expression; - _expectedName = expectedName; + _observedPropertyName = expectedName; _beforeChanged = beforeChanged; } @@ -59,7 +49,7 @@ public IDisposable Subscribe(IObserver> observe { ArgumentExceptionHelper.ThrowIfNull(observer); - return new Subscription(_sender, _expression, _expectedName, _beforeChanged, observer); + return new Subscription(_sender, _expression, _observedPropertyName, _beforeChanged, observer); } /// @@ -68,20 +58,14 @@ public IDisposable Subscribe(IObserver> observe /// private sealed class Subscription : IDisposable { - /// - /// The before-change source, or when observing after-change. - /// + /// The before-change source, or when observing after-change. private readonly INotifyPropertyChanging? _changing; - /// - /// The after-change source, or when observing before-change. - /// + /// The after-change source, or when observing before-change. private readonly INotifyPropertyChanged? _changed; - /// - /// The observed property name (an empty notified name means "all properties"). - /// - private readonly string _expectedName; + /// The observed property name (an empty notified name means "all properties"). + private readonly string _observedPropertyName; /// /// The change forwarded on every matching notification. It is constant for the subscription @@ -89,14 +73,10 @@ private sealed class Subscription : IDisposable /// private readonly IObservedChange _change; - /// - /// The downstream observer. Set to on disposal. - /// + /// The downstream observer. Set to on disposal. private IObserver>? _observer; - /// - /// Initializes a new instance of the class and wires the change event. - /// + /// Initializes a new instance of the class and wires the change event. /// The source object raising the notifications. /// The expression surfaced on the emitted observed change. /// The observed property name. @@ -109,7 +89,7 @@ public Subscription( bool beforeChanged, IObserver> observer) { - _expectedName = expectedName; + _observedPropertyName = expectedName; _observer = observer; _change = new ObservedChange(sender, expression, default); @@ -154,31 +134,23 @@ public void Dispose() /// if the notification applies to the observed property. private bool Matches(string? notifiedName) => string.IsNullOrEmpty(notifiedName) - || string.Equals(notifiedName, _expectedName, StringComparison.InvariantCulture); + || string.Equals(notifiedName, _observedPropertyName, StringComparison.InvariantCulture); - /// - /// Handles , forwarding the change when the name matches. - /// + /// Handles , forwarding the change when the name matches. /// The event sender. /// The property-changed event arguments. - private void OnPropertyChanged(object? sender, PropertyChangedEventArgs e) - { - if (!Matches(e.PropertyName)) - { - return; - } - - Volatile.Read(ref _observer)?.OnNext(_change); - } + private void OnPropertyChanged(object? sender, PropertyChangedEventArgs e) => Forward(e.PropertyName); - /// - /// Handles , forwarding the change when the name matches. - /// + /// Handles , forwarding the change when the name matches. /// The event sender. /// The property-changing event arguments. - private void OnPropertyChanging(object? sender, PropertyChangingEventArgs e) + private void OnPropertyChanging(object? sender, PropertyChangingEventArgs e) => Forward(e.PropertyName); + + /// Forwards the change to the observer when the notified name matches the observed property. + /// The property name carried by the notification. + private void Forward(string? notifiedName) { - if (!Matches(e.PropertyName)) + if (!Matches(notifiedName)) { return; } diff --git a/src/ReactiveUI.Binding/Observables/PropertyChangingObservable.cs b/src/ReactiveUI.Binding/Observables/PropertyChangingObservable.cs index 99802e4..d1edfde 100644 --- a/src/ReactiveUI.Binding/Observables/PropertyChangingObservable.cs +++ b/src/ReactiveUI.Binding/Observables/PropertyChangingObservable.cs @@ -16,24 +16,16 @@ namespace ReactiveUI.Binding.Observables; [EditorBrowsable(EditorBrowsableState.Never)] public sealed class PropertyChangingObservable : IObservable { - /// - /// The source object implementing . - /// + /// The source object implementing . private readonly INotifyPropertyChanging _source; - /// - /// The name of the property to observe. - /// + /// The name of the property to observe. private readonly string _propertyName; - /// - /// A delegate that reads the current property value from the source. - /// + /// A delegate that reads the current property value from the source. private readonly Func _getter; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The object implementing . /// The property name to observe. /// A delegate that reads the property value from the source. @@ -58,26 +50,16 @@ public IDisposable Subscribe(IObserver observer) return new Subscription(this, observer); } - /// - /// Manages the event subscription for a single observer. - /// + /// Manages the event subscription for a single observer. internal sealed class Subscription : IDisposable { - /// - /// The parent observable that owns the source and property metadata. - /// + /// The parent observable that owns the source and property metadata. private readonly PropertyChangingObservable _parent; - /// - /// The downstream observer. Set to on disposal. - /// + /// The downstream observer. Set to on disposal. private IObserver? _observer; - /// - /// Initializes a new instance of the class. - /// Subscribes to the event - /// and emits the initial property value. - /// + /// Initializes a new instance of the class, subscribing and emitting the initial value. /// The parent observable. /// The downstream observer. public Subscription(PropertyChangingObservable parent, IObserver observer) @@ -103,18 +85,13 @@ public void Dispose() _parent._source.PropertyChanging -= OnPropertyChanging; } - /// - /// Atomically nulls the observer, returning whether it was previously non-null. - /// + /// Atomically nulls the observer, returning whether it was previously non-null. /// if this is the first disposal; otherwise . [ExcludeFromCodeCoverage] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal bool TrySetDisposed() => Interlocked.Exchange(ref _observer, null) != null; + internal bool TrySetDisposed() => Interlocked.Exchange(ref _observer, null) is not null; - /// - /// Handles the event - /// and forwards the current property value to the observer. - /// + /// Handles the event and forwards the current property value to the observer. /// The event sender. /// The event arguments containing the property name. private void OnPropertyChanging(object? sender, PropertyChangingEventArgs e) diff --git a/src/ReactiveUI.Binding/Observables/PropertyObservable.cs b/src/ReactiveUI.Binding/Observables/PropertyObservable.cs index d31500f..60d6785 100644 --- a/src/ReactiveUI.Binding/Observables/PropertyObservable.cs +++ b/src/ReactiveUI.Binding/Observables/PropertyObservable.cs @@ -15,30 +15,19 @@ namespace ReactiveUI.Binding.Observables; [EditorBrowsable(EditorBrowsableState.Never)] public sealed class PropertyObservable : IObservable { - /// - /// The source object implementing . - /// + /// The source object implementing . private readonly INotifyPropertyChanged _source; - /// - /// The name of the property to observe. - /// + /// The name of the property to observe. private readonly string _propertyName; - /// - /// A delegate that reads the current property value from the source. The value may be - /// for reference-typed properties. - /// + /// A delegate that reads the current property value from the source. The value may be for reference-typed properties. private readonly Func _getter; - /// - /// Whether to suppress duplicate consecutive values. - /// + /// Whether to suppress duplicate consecutive values. private readonly bool _distinctUntilChanged; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The object implementing . /// The property name to observe. /// A delegate that reads the property value from the source. @@ -66,24 +55,16 @@ public IDisposable Subscribe(IObserver observer) return new Subscription(this, observer); } - /// - /// Manages the event subscription for a single observer, with optional distinct-until-changed filtering. - /// + /// Manages the event subscription for a single observer, with optional distinct-until-changed filtering. internal sealed class Subscription : IDisposable { - /// - /// The parent observable that owns the source and property metadata. - /// + /// The parent observable that owns the source and property metadata. private readonly PropertyObservable _parent; - /// - /// The equality comparer used for distinct-until-changed filtering. - /// + /// The equality comparer used for distinct-until-changed filtering. private readonly EqualityComparer _comparer; - /// - /// The downstream observer. Set to on disposal. - /// + /// The downstream observer. Set to on disposal. private IObserver? _observer; /// @@ -92,16 +73,10 @@ internal sealed class Subscription : IDisposable /// private T? _lastValue; - /// - /// Whether at least one value has been emitted. - /// + /// Whether at least one value has been emitted. private bool _hasValue; - /// - /// Initializes a new instance of the class. - /// Subscribes to the event - /// and emits the initial property value. - /// + /// Initializes a new instance of the class, subscribing and emitting the initial value. /// The parent observable. /// The downstream observer. public Subscription(PropertyObservable parent, IObserver observer) @@ -130,13 +105,11 @@ public void Dispose() _parent._source.PropertyChanged -= OnPropertyChanged; } - /// - /// Atomically nulls the observer, returning whether it was previously non-null. - /// + /// Atomically nulls the observer, returning whether it was previously non-null. /// if this is the first disposal; otherwise . [ExcludeFromCodeCoverage] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal bool TrySetDisposed() => Interlocked.Exchange(ref _observer, null) != null; + internal bool TrySetDisposed() => Interlocked.Exchange(ref _observer, null) is not null; /// /// Handles the event diff --git a/src/ReactiveUI.Binding/Observables/ReturnObservable.cs b/src/ReactiveUI.Binding/Observables/ReturnObservable.cs index 498b96d..7105e10 100644 --- a/src/ReactiveUI.Binding/Observables/ReturnObservable.cs +++ b/src/ReactiveUI.Binding/Observables/ReturnObservable.cs @@ -6,10 +6,7 @@ namespace ReactiveUI.Binding.Observables; -/// -/// An observable that emits a single value and then completes. -/// Lightweight replacement for Observable.Return<T>(value). -/// +/// An observable that emits a single value and then completes. Lightweight replacement for Observable.Return<T>(value). /// The type of the value. [EditorBrowsable(EditorBrowsableState.Never)] public sealed class ReturnObservable : IObservable @@ -20,9 +17,7 @@ public sealed class ReturnObservable : IObservable /// private readonly T? _value; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The value to emit; may be for reference types. public ReturnObservable(T? value) => _value = value; diff --git a/src/ReactiveUI.Binding/Observables/RxBindingExtensions.cs b/src/ReactiveUI.Binding/Observables/RxBindingExtensions.cs index 5f97c65..d413fb0 100644 --- a/src/ReactiveUI.Binding/Observables/RxBindingExtensions.cs +++ b/src/ReactiveUI.Binding/Observables/RxBindingExtensions.cs @@ -14,9 +14,7 @@ namespace ReactiveUI.Binding.Observables; [EditorBrowsable(EditorBrowsableState.Never)] public static class RxBindingExtensions { - /// - /// Subscribes to the observable with an action for OnNext. - /// + /// Subscribes to the observable with an action for OnNext. /// The element type. /// The source observable. /// The action to invoke on each element. @@ -29,68 +27,56 @@ public static IDisposable Subscribe(IObservable source, Action onNext) return source.Subscribe(new ActionObserver(onNext)); } - /// - /// Projects each element using a selector function. - /// - /// The source element type. - /// The projected element type. - /// The source observable. - /// The projection function. - /// A projected observable. - public static IObservable Select( - this IObservable source, - Func selector) => new SelectObservable(source, selector); - - /// - /// Flattens an observable of observables by subscribing to the most recent inner observable. - /// - /// The element type. - /// The source observable of observables. - /// A flattened observable. - public static IObservable Switch(this IObservable> source) => new SwitchObservable(source); - - /// - /// Skips the first elements. - /// + /// Skips the first elements. /// The element type. /// The source observable. /// The number of elements to skip. /// An observable that skips elements. public static IObservable Skip(IObservable source, int count) => new SkipObservable(source, count); - /// - /// Suppresses consecutive duplicate values. - /// - /// The element type. - /// The source observable. - /// An observable with distinct consecutive values. - public static IObservable DistinctUntilChanged(this IObservable source) => - new DistinctUntilChangedObservable(source); - - /// - /// Merges multiple observables into one. - /// + /// Merges multiple observables into one. /// The element type. /// The source observables. /// A merged observable. public static IObservable Merge(params IObservable[] sources) => new MergeObservable(sources); - /// - /// An observer that delegates to an . - /// Errors and completion are intentionally ignored for binding scenarios. - /// + /// Provides Switch extension members for . + /// The element type. + /// The source observable of observables. + extension(IObservable> source) + { + /// Flattens an observable of observables by subscribing to the most recent inner observable. + /// A flattened observable. + public IObservable Switch() => new SwitchObservable(source); + } + + /// Provides Select and DistinctUntilChanged extension members for . + /// The element type. + /// The source observable. + extension(IObservable source) + { + /// Projects each element using a selector function. + /// The projected element type. + /// The projection function. + /// A projected observable. + public IObservable Select(Func selector) => + new SelectObservable(source, selector); + + /// Suppresses consecutive duplicate values. + /// An observable with distinct consecutive values. + public IObservable DistinctUntilChanged() => + new DistinctUntilChangedObservable(source); + } + + /// An observer that delegates to an . Errors and completion are intentionally ignored for binding scenarios. /// The element type. [ExcludeFromCodeCoverage] private sealed class ActionObserver : IObserver { - /// - /// The action to invoke for each element. - /// + /// The action to invoke for each element. private readonly Action _onNext; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The action to invoke for each element. public ActionObserver(Action onNext) => _onNext = onNext; diff --git a/src/ReactiveUI.Binding/Observables/SelectObservable.cs b/src/ReactiveUI.Binding/Observables/SelectObservable.cs index 44d59e2..ba0eb7e 100644 --- a/src/ReactiveUI.Binding/Observables/SelectObservable.cs +++ b/src/ReactiveUI.Binding/Observables/SelectObservable.cs @@ -6,28 +6,19 @@ namespace ReactiveUI.Binding.Observables; -/// -/// Lightweight Select (map/projection) operator. -/// Replacement for System.Reactive.Linq.Observable.Select. -/// +/// Lightweight Select (map/projection) operator. Replacement for System.Reactive.Linq.Observable.Select. /// The source element type. /// The projected element type. [EditorBrowsable(EditorBrowsableState.Never)] public sealed class SelectObservable : IObservable { - /// - /// The upstream source observable. - /// + /// The upstream source observable. private readonly IObservable _source; - /// - /// The projection function applied to each element. - /// + /// The projection function applied to each element. private readonly Func _selector; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The source observable. /// The projection function. public SelectObservable(IObservable source, Func selector) @@ -46,31 +37,16 @@ public IDisposable Subscribe(IObserver observer) return _source.Subscribe(new SelectObserver(observer, _selector)); } - /// - /// Observer that applies the projection function to each source element. - /// - private sealed class SelectObserver : IObserver + /// Observer that applies the projection function to each source element. + /// The downstream observer. + /// The projection function. + private sealed class SelectObserver(IObserver observer, Func selector) : IObserver { - /// - /// The downstream observer receiving projected values. - /// - private readonly IObserver _observer; - - /// - /// The projection function applied to each element. - /// - private readonly Func _selector; + /// The downstream observer receiving projected values. + private readonly IObserver _observer = observer; - /// - /// Initializes a new instance of the class. - /// - /// The downstream observer. - /// The projection function. - public SelectObserver(IObserver observer, Func selector) - { - _observer = observer; - _selector = selector; - } + /// The projection function applied to each element. + private readonly Func _selector = selector; /// public void OnNext(TSource value) => _observer.OnNext(_selector(value)); diff --git a/src/ReactiveUI.Binding/Observables/SerialDisposable.cs b/src/ReactiveUI.Binding/Observables/SerialDisposable.cs index 352dddb..ffc2b44 100644 --- a/src/ReactiveUI.Binding/Observables/SerialDisposable.cs +++ b/src/ReactiveUI.Binding/Observables/SerialDisposable.cs @@ -13,14 +13,10 @@ namespace ReactiveUI.Binding.Observables; [EditorBrowsable(EditorBrowsableState.Never)] public sealed class SerialDisposable : IDisposable { - /// - /// The current inner disposable. Swapped atomically when a new value is assigned. - /// + /// The current inner disposable. Swapped atomically when a new value is assigned. private IDisposable? _current; - /// - /// Guard flag to ensure disposal occurs exactly once (0 = not disposed, 1 = disposed). - /// + /// Guard flag to ensure disposal occurs exactly once (0 = not disposed, 1 = disposed). private int _disposed; /// @@ -34,7 +30,7 @@ public IDisposable? Disposable { SwapCurrent(value)?.Dispose(); - if (_disposed != 1) + if (Volatile.Read(ref _disposed) != 1) { return; } @@ -54,26 +50,20 @@ public void Dispose() TakeCurrent()?.Dispose(); } - /// - /// Atomically marks this instance as disposed. - /// + /// Atomically marks this instance as disposed. /// if this is the first disposal; otherwise . [ExcludeFromCodeCoverage] [MethodImpl(MethodImplOptions.AggressiveInlining)] internal bool TrySetDisposed() => Interlocked.Exchange(ref _disposed, 1) == 0; - /// - /// Atomically swaps the current disposable with the given value. - /// + /// Atomically swaps the current disposable with the given value. /// The new disposable. /// The previous disposable, or . [ExcludeFromCodeCoverage] [MethodImpl(MethodImplOptions.AggressiveInlining)] internal IDisposable? SwapCurrent(IDisposable? value) => Interlocked.Exchange(ref _current, value); - /// - /// Atomically takes the current disposable, returning it exactly once. - /// + /// Atomically takes the current disposable, returning it exactly once. /// The current disposable if present; otherwise . [ExcludeFromCodeCoverage] [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ReactiveUI.Binding/Observables/SkipObservable.cs b/src/ReactiveUI.Binding/Observables/SkipObservable.cs index b2c38bc..ddb565c 100644 --- a/src/ReactiveUI.Binding/Observables/SkipObservable.cs +++ b/src/ReactiveUI.Binding/Observables/SkipObservable.cs @@ -6,27 +6,18 @@ namespace ReactiveUI.Binding.Observables; -/// -/// Lightweight Skip operator that suppresses the first N elements. -/// Replacement for System.Reactive.Linq.Observable.Skip. -/// +/// Lightweight Skip operator that suppresses the first N elements. Replacement for System.Reactive.Linq.Observable.Skip. /// The element type. [EditorBrowsable(EditorBrowsableState.Never)] public sealed class SkipObservable : IObservable { - /// - /// The upstream source observable. - /// + /// The upstream source observable. private readonly IObservable _source; - /// - /// The number of elements to skip. - /// + /// The number of elements to skip. private readonly int _count; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The source observable. /// The number of elements to skip. public SkipObservable(IObservable source, int count) @@ -44,31 +35,16 @@ public IDisposable Subscribe(IObserver observer) return _source.Subscribe(new SkipObserver(observer, _count)); } - /// - /// Observer that skips the first N elements before forwarding to the downstream observer. - /// - private sealed class SkipObserver : IObserver + /// Observer that skips the first N elements before forwarding to the downstream observer. + /// The downstream observer. + /// The number of elements to skip. + private sealed class SkipObserver(IObserver observer, int count) : IObserver { - /// - /// The downstream observer. - /// - private readonly IObserver _observer; - - /// - /// The number of elements still to skip. - /// - private int _remaining; + /// The downstream observer. + private readonly IObserver _observer = observer; - /// - /// Initializes a new instance of the class. - /// - /// The downstream observer. - /// The number of elements to skip. - public SkipObserver(IObserver observer, int count) - { - _observer = observer; - _remaining = count; - } + /// The number of elements still to skip. + private int _remaining = count; /// public void OnNext(T value) diff --git a/src/ReactiveUI.Binding/Observables/StartWithObservable.cs b/src/ReactiveUI.Binding/Observables/StartWithObservable.cs index 91cd114..cf78c4d 100644 --- a/src/ReactiveUI.Binding/Observables/StartWithObservable.cs +++ b/src/ReactiveUI.Binding/Observables/StartWithObservable.cs @@ -14,19 +14,13 @@ namespace ReactiveUI.Binding.Observables; [EditorBrowsable(EditorBrowsableState.Never)] public sealed class StartWithObservable : IObservable { - /// - /// The upstream source observable. - /// + /// The upstream source observable. private readonly IObservable _source; - /// - /// The value emitted before the source sequence. - /// + /// The value emitted before the source sequence. private readonly T _value; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The source observable. /// The value to emit before the source sequence. public StartWithObservable(IObservable source, T value) diff --git a/src/ReactiveUI.Binding/Observables/SwitchObservable.cs b/src/ReactiveUI.Binding/Observables/SwitchObservable.cs index 3d578dd..b419fe3 100644 --- a/src/ReactiveUI.Binding/Observables/SwitchObservable.cs +++ b/src/ReactiveUI.Binding/Observables/SwitchObservable.cs @@ -15,14 +15,10 @@ namespace ReactiveUI.Binding.Observables; [EditorBrowsable(EditorBrowsableState.Never)] public sealed class SwitchObservable : IObservable { - /// - /// The outer observable of inner observables. - /// + /// The outer observable of inner observables. private readonly IObservable> _source; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The outer observable of inner observables. public SwitchObservable(IObservable> source) { @@ -40,35 +36,23 @@ public IDisposable Subscribe(IObserver observer) return subscription; } - /// - /// Manages the outer subscription and switches inner subscriptions as new inner observables arrive. - /// + /// Manages the outer subscription and switches inner subscriptions as new inner observables arrive. private sealed class SwitchSubscription : IObserver>, IDisposable { - /// - /// The downstream observer receiving values from the current inner observable. - /// + /// The downstream observer receiving values from the current inner observable. private readonly IObserver _observer; - /// - /// The current inner subscription. Disposed and replaced when a new inner observable arrives. - /// + /// The current inner subscription. Disposed and replaced when a new inner observable arrives. private IDisposable? _innerSubscription; - /// - /// Guard flag to ensure disposal occurs exactly once (0 = not disposed, 1 = disposed). - /// + /// Guard flag to ensure disposal occurs exactly once (0 = not disposed, 1 = disposed). private int _disposed; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The downstream observer. public SwitchSubscription(IObserver observer) => _observer = observer; - /// - /// Gets or sets the outer subscription. Set after construction to avoid passing through the constructor. - /// + /// Gets or sets the outer subscription. Set after construction to avoid passing through the constructor. public IDisposable? OuterSubscription { get; set; } /// @@ -122,31 +106,25 @@ public void Dispose() DisposeSubscriptions(); } - /// - /// Atomically marks this instance as disposed. - /// + /// Atomically marks this instance as disposed. /// if this is the first disposal; otherwise . [ExcludeFromCodeCoverage] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal bool TrySetDisposed() => Interlocked.Exchange(ref _disposed, 1) == 0; + private bool TrySetDisposed() => Interlocked.Exchange(ref _disposed, 1) == 0; - /// - /// Atomically takes the inner subscription, returning it exactly once. - /// + /// Atomically takes the inner subscription, returning it exactly once. /// The inner subscription if present; otherwise . [ExcludeFromCodeCoverage] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal IDisposable? TakeInnerSubscription() => Interlocked.Exchange(ref _innerSubscription, null); + private IDisposable? TakeInnerSubscription() => Interlocked.Exchange(ref _innerSubscription, null); - /// - /// Atomically sets the inner subscription if the slot is currently empty. - /// + /// Atomically sets the inner subscription if the slot is currently empty. /// The subscription to store. /// if the slot was empty and the value was stored; otherwise . [ExcludeFromCodeCoverage] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal bool TrySetInnerSubscription(IDisposable subscription) => - Interlocked.CompareExchange(ref _innerSubscription, subscription, null) == null; + private bool TrySetInnerSubscription(IDisposable subscription) => + Interlocked.CompareExchange(ref _innerSubscription, subscription, null) is null; /// /// Disposes a newly created subscription if a concurrent OnNext or Dispose has already @@ -178,19 +156,13 @@ private void DisposeSubscriptions() TakeInnerSubscription()?.Dispose(); } - /// - /// Observer for the current inner observable that forwards values to the downstream observer. - /// + /// Observer for the current inner observable that forwards values to the downstream observer. private sealed class InnerObserver : IObserver { - /// - /// The parent switch subscription. - /// + /// The parent switch subscription. private readonly SwitchSubscription _parent; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The parent switch subscription. public InnerObserver(SwitchSubscription parent) => _parent = parent; diff --git a/src/ReactiveUI.Binding/Observables/WhereObservable.cs b/src/ReactiveUI.Binding/Observables/WhereObservable.cs index ea9cba2..67b64d2 100644 --- a/src/ReactiveUI.Binding/Observables/WhereObservable.cs +++ b/src/ReactiveUI.Binding/Observables/WhereObservable.cs @@ -14,19 +14,13 @@ namespace ReactiveUI.Binding.Observables; [EditorBrowsable(EditorBrowsableState.Never)] public sealed class WhereObservable : IObservable { - /// - /// The upstream source observable. - /// + /// The upstream source observable. private readonly IObservable _source; - /// - /// The predicate that determines which values are forwarded. - /// + /// The predicate that determines which values are forwarded. private readonly Func _predicate; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The source observable. /// The predicate that determines which values are forwarded. public WhereObservable(IObservable source, Func predicate) @@ -45,31 +39,16 @@ public IDisposable Subscribe(IObserver observer) return _source.Subscribe(new WhereObserver(observer, _predicate)); } - /// - /// Observer that forwards only values matching the predicate. - /// - private sealed class WhereObserver : IObserver + /// Observer that forwards only values matching the predicate. + /// The downstream observer. + /// The predicate that determines which values are forwarded. + private sealed class WhereObserver(IObserver observer, Func predicate) : IObserver { - /// - /// The downstream observer. - /// - private readonly IObserver _observer; - - /// - /// The predicate that determines which values are forwarded. - /// - private readonly Func _predicate; + /// The downstream observer. + private readonly IObserver _observer = observer; - /// - /// Initializes a new instance of the class. - /// - /// The downstream observer. - /// The predicate that determines which values are forwarded. - public WhereObserver(IObserver observer, Func predicate) - { - _observer = observer; - _predicate = predicate; - } + /// The predicate that determines which values are forwarded. + private readonly Func _predicate = predicate; /// public void OnNext(T value) diff --git a/src/ReactiveUI.Binding/Polyfills/CallerArgumentExpressionAttribute.cs b/src/ReactiveUI.Binding/Polyfills/CallerArgumentExpressionAttribute.cs index d7d7c5b..cf2b9a1 100644 --- a/src/ReactiveUI.Binding/Polyfills/CallerArgumentExpressionAttribute.cs +++ b/src/ReactiveUI.Binding/Polyfills/CallerArgumentExpressionAttribute.cs @@ -10,25 +10,19 @@ namespace System.Runtime.CompilerServices; -/// -/// Indicates that a parameter captures the expression passed for another parameter as a string. -/// +/// Indicates that a parameter captures the expression passed for another parameter as a string. [ExcludeFromCodeCoverage] [DebuggerNonUserCode] [AttributeUsage(AttributeTargets.Parameter)] internal sealed class CallerArgumentExpressionAttribute : Attribute { - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The name of the parameter whose expression should be captured as a string. public CallerArgumentExpressionAttribute(string parameterName) => ParameterName = parameterName; - /// - /// Gets the name of the parameter whose expression should be captured as a string. - /// - public string ParameterName { get; } + /// Gets the name of the parameter whose expression should be captured as a string. + internal string ParameterName { get; } } #else diff --git a/src/ReactiveUI.Binding/Polyfills/DoesNotReturnIfAttribute.cs b/src/ReactiveUI.Binding/Polyfills/DoesNotReturnIfAttribute.cs index 65a9aa7..ef74e18 100644 --- a/src/ReactiveUI.Binding/Polyfills/DoesNotReturnIfAttribute.cs +++ b/src/ReactiveUI.Binding/Polyfills/DoesNotReturnIfAttribute.cs @@ -9,19 +9,13 @@ namespace System.Diagnostics.CodeAnalysis; -/// -/// Specifies that the method will not return if the associated -/// parameter is passed the specified value. -/// +/// Specifies that the method will not return if the associated parameter is passed the specified value. [ExcludeFromCodeCoverage] [DebuggerNonUserCode] [AttributeUsage(AttributeTargets.Parameter)] internal sealed class DoesNotReturnIfAttribute : Attribute { - /// - /// Initializes a new instance of the - /// class with the specified parameter value. - /// + /// Initializes a new instance of the class with the specified parameter value. /// /// The condition parameter value. Code after the method is considered unreachable /// by diagnostics if the argument to the associated parameter matches this value. @@ -33,7 +27,7 @@ public DoesNotReturnIfAttribute(bool parameterValue) => /// Gets a value indicating whether code after the method is considered unreachable /// by diagnostics if the argument to the associated parameter matches this value. /// - public bool ParameterValue { get; } + internal bool ParameterValue { get; } } #else [assembly: TypeForwardedTo(typeof(DoesNotReturnIfAttribute))] diff --git a/src/ReactiveUI.Binding/Polyfills/DynamicallyAccessedMemberTypes.cs b/src/ReactiveUI.Binding/Polyfills/DynamicallyAccessedMemberTypes.cs index 6f81c0c..a703d67 100644 --- a/src/ReactiveUI.Binding/Polyfills/DynamicallyAccessedMemberTypes.cs +++ b/src/ReactiveUI.Binding/Polyfills/DynamicallyAccessedMemberTypes.cs @@ -13,88 +13,55 @@ namespace System.Diagnostics.CodeAnalysis; /// bitwise combination of its member values. /// [Flags] -[SuppressMessage("Roslynator", "RCS1157:Composite enum value contains undefined flag", Justification = "This is a polyfill class matching .NET")] -[SuppressMessage("Major Code Smell", "S4070:Non-flags enums should not be marked with \"FlagsAttribute\"", Justification = "This is a polyfill class matching .NET")] +[SuppressMessage("Design", "SST2303:Flags enum members should be distinct bit values", Justification = "Mirrors the framework enum bit-for-bit, including its composite members.")] internal enum DynamicallyAccessedMemberTypes { - /// - /// Specifies no members. - /// + /// Specifies no members. None = 0, - /// - /// Specifies the default, parameterless public constructor. - /// + /// Specifies the default, parameterless public constructor. PublicParameterlessConstructor = 0x_0001, - /// - /// Specifies all public constructors. - /// + /// Specifies all public constructors. PublicConstructors = 0x_0002 | PublicParameterlessConstructor, - /// - /// Specifies all non-public constructors. - /// + /// Specifies all non-public constructors. NonPublicConstructors = 0x_0004, - /// - /// Specifies all public methods. - /// + /// Specifies all public methods. PublicMethods = 0x_0008, - /// - /// Specifies all non-public methods. - /// + /// Specifies all non-public methods. NonPublicMethods = 0x_0010, - /// - /// Specifies all public fields. - /// + /// Specifies all public fields. PublicFields = 0x_0020, - /// - /// Specifies all non-public fields. - /// + /// Specifies all non-public fields. NonPublicFields = 0x_0040, - /// - /// Specifies all public nested types. - /// + /// Specifies all public nested types. PublicNestedTypes = 0x_0080, - /// - /// Specifies all non-public nested types. - /// + /// Specifies all non-public nested types. NonPublicNestedTypes = 0x_0100, - /// - /// Specifies all public properties. - /// + /// Specifies all public properties. PublicProperties = 0x_0200, - /// - /// Specifies all non-public properties. - /// + /// Specifies all non-public properties. NonPublicProperties = 0x_0400, - /// - /// Specifies all public events. - /// + /// Specifies all public events. PublicEvents = 0x_0800, - /// - /// Specifies all non-public events. - /// + /// Specifies all non-public events. NonPublicEvents = 0x_1000, - /// - /// Specifies all interfaces implemented by the type. - /// + /// Specifies all interfaces implemented by the type. Interfaces = 0x_2000, - /// - /// Specifies all members. - /// + /// Specifies all members. All = ~None, } diff --git a/src/ReactiveUI.Binding/Polyfills/DynamicallyAccessedMembersAttribute.cs b/src/ReactiveUI.Binding/Polyfills/DynamicallyAccessedMembersAttribute.cs index 69b55a4..c2e2775 100644 --- a/src/ReactiveUI.Binding/Polyfills/DynamicallyAccessedMembersAttribute.cs +++ b/src/ReactiveUI.Binding/Polyfills/DynamicallyAccessedMembersAttribute.cs @@ -8,38 +8,29 @@ namespace System.Diagnostics.CodeAnalysis; -/// -/// Indicates that certain members on a specified are accessed dynamically, -/// for example through . -/// +/// Indicates that certain members on a specified are accessed dynamically, for example through . [ExcludeFromCodeCoverage] [DebuggerNonUserCode] [AttributeUsage( - validOn: AttributeTargets.Class | - AttributeTargets.Field | - AttributeTargets.GenericParameter | - AttributeTargets.Interface | - AttributeTargets.Method | - AttributeTargets.Parameter | - AttributeTargets.Property | - AttributeTargets.ReturnValue | - AttributeTargets.Struct, + validOn: AttributeTargets.Class + | AttributeTargets.Field + | AttributeTargets.GenericParameter + | AttributeTargets.Interface + | AttributeTargets.Method + | AttributeTargets.Parameter + | AttributeTargets.Property + | AttributeTargets.ReturnValue + | AttributeTargets.Struct, Inherited = false)] internal sealed class DynamicallyAccessedMembersAttribute : Attribute { - /// - /// Initializes a new instance of the class - /// with the specified member types. - /// + /// Initializes a new instance of the class with the specified member types. /// The types of members dynamically accessed. public DynamicallyAccessedMembersAttribute(DynamicallyAccessedMemberTypes memberTypes) => MemberTypes = memberTypes; - /// - /// Gets the which specifies the type - /// of members dynamically accessed. - /// - public DynamicallyAccessedMemberTypes MemberTypes { get; } + /// Gets the which specifies the type of members dynamically accessed. + internal DynamicallyAccessedMemberTypes MemberTypes { get; } } #else diff --git a/src/ReactiveUI.Binding/Polyfills/Index.cs b/src/ReactiveUI.Binding/Polyfills/Index.cs new file mode 100644 index 0000000..ae262c1 --- /dev/null +++ b/src/ReactiveUI.Binding/Polyfills/Index.cs @@ -0,0 +1,97 @@ +// Copyright (c) 2019-2026 ReactiveUI Association Incorporated. All rights reserved. +// ReactiveUI Association Incorporated licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +// Polyfill implementation adapted from SimonCropp/Polyfill +// https://github.com/SimonCropp/Polyfill +#if !NET +using System.Diagnostics.CodeAnalysis; + +namespace System; + +/// +/// Represents a type that can be used to index a collection either from the start or the end. +/// Polyfill for the framework targets that predate System.Index, enabling the ^ index operator. +/// +[ExcludeFromCodeCoverage] +internal readonly struct Index : IEquatable +{ + /// The encoded value; non-negative is measured from the start, the bitwise complement is measured from the end. + private readonly int _value; + + /// Initializes a new instance of the struct. + /// The index value. Must be zero or positive. + /// Indicates whether the index is counted from the start or the end. + public Index(int value, bool fromEnd = false) + { + if (value < 0) + { + throw new ArgumentOutOfRangeException(nameof(value), "Non-negative number required."); + } + + _value = fromEnd ? ~value : value; + } + + /// Gets an that points at the first element of a collection. + internal static Index Start => new(0); + + /// Gets an that points beyond the last element of a collection. + internal static Index End => new(0, true); + + /// Gets the index value (without the from-end flag). + internal int Value => _value < 0 ? ~_value : _value; + + /// Gets a value indicating whether the index is counted from the end of a collection. + internal bool IsFromEnd => _value < 0; + + /// Converts an integer into an measured from the start. + /// The zero-based index from the start. + public static implicit operator Index(int value) => new(value); + + /// Determines whether two indexes are equal. + /// The first index. + /// The second index. + /// if the indexes are equal; otherwise . + public static bool operator ==(Index left, Index right) => left.Equals(right); + + /// Determines whether two indexes are not equal. + /// The first index. + /// The second index. + /// if the indexes are not equal; otherwise . + public static bool operator !=(Index left, Index right) => !left.Equals(right); + + /// + public bool Equals(Index other) => _value == other._value; + + /// + public override bool Equals(object? obj) => obj is Index other && _value == other._value; + + /// + public override int GetHashCode() => _value; + + /// Creates an measured from the start of a collection. + /// The zero-based index from the start. + /// The created . + internal static Index FromStart(int value) => new(value); + + /// Creates an measured from the end of a collection. + /// The index from the end (1 refers to the last element). + /// The created . + internal static Index FromEnd(int value) => new(value, true); + + /// Calculates the offset from the start of a collection of the supplied length. + /// The length of the collection. + /// The offset from the start of the collection. + internal int GetOffset(int length) + { + var offset = _value; + if (IsFromEnd) + { + offset += length + 1; + } + + return offset; + } +} + +#endif diff --git a/src/ReactiveUI.Binding/Polyfills/IsExternalInit.cs b/src/ReactiveUI.Binding/Polyfills/IsExternalInit.cs index 89687e0..b8afe37 100644 --- a/src/ReactiveUI.Binding/Polyfills/IsExternalInit.cs +++ b/src/ReactiveUI.Binding/Polyfills/IsExternalInit.cs @@ -10,12 +10,10 @@ namespace System.Runtime.CompilerServices; -/// -/// Reserved to be used by the compiler for tracking metadata. -/// This class should not be used by developers in source code. -/// +/// Reserved to be used by the compiler for tracking metadata. This class should not be used by developers in source code. [ExcludeFromCodeCoverage] [DebuggerNonUserCode] +[SuppressMessage("Design", "SST1436:Empty type", Justification = "The compiler requires this exact empty type to emit init accessors on targets that do not ship it.")] internal static class IsExternalInit; #else diff --git a/src/ReactiveUI.Binding/Polyfills/MaybeNullWhenAttribute.cs b/src/ReactiveUI.Binding/Polyfills/MaybeNullWhenAttribute.cs index 80bfbb3..d98897b 100644 --- a/src/ReactiveUI.Binding/Polyfills/MaybeNullWhenAttribute.cs +++ b/src/ReactiveUI.Binding/Polyfills/MaybeNullWhenAttribute.cs @@ -9,18 +9,13 @@ namespace System.Diagnostics.CodeAnalysis; -/// -/// Specifies that when a method returns , -/// the parameter may be even if the corresponding type disallows it. -/// +/// Specifies that when a method returns , the parameter may be even if the corresponding type disallows it. [ExcludeFromCodeCoverage] [DebuggerNonUserCode] [AttributeUsage(AttributeTargets.Parameter)] internal sealed class MaybeNullWhenAttribute : Attribute { - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// /// The return value condition. If the method returns this value, /// the associated parameter may be . @@ -31,7 +26,7 @@ internal sealed class MaybeNullWhenAttribute : Attribute /// Gets a value indicating whether the return condition has been satisfied. /// If the method returns this value, the associated parameter may be . /// - public bool ReturnValue { get; } + internal bool ReturnValue { get; } } #else diff --git a/src/ReactiveUI.Binding/Polyfills/MemberNotNullAttribute.cs b/src/ReactiveUI.Binding/Polyfills/MemberNotNullAttribute.cs index 50ae9aa..75876eb 100644 --- a/src/ReactiveUI.Binding/Polyfills/MemberNotNullAttribute.cs +++ b/src/ReactiveUI.Binding/Polyfills/MemberNotNullAttribute.cs @@ -10,37 +10,28 @@ namespace System.Diagnostics.CodeAnalysis; -/// -/// Specifies that the method or property will ensure that the listed field and property members have -/// not- values. -/// +/// Specifies that the method or property will ensure that the listed field and property members have not- values. [ExcludeFromCodeCoverage] [DebuggerNonUserCode] [AttributeUsage( - validOn: Targets.Method | - Targets.Property, + validOn: Targets.Method + | Targets.Property, Inherited = false, AllowMultiple = true)] internal sealed class MemberNotNullAttribute : Attribute { - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// Field or property member name. - public MemberNotNullAttribute([SuppressMessage("Design", "CA1019:Define accessors for attribute arguments", Justification = "For polyfill")] string member) => + public MemberNotNullAttribute(string member) => Members = [member]; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// Field or property member names. public MemberNotNullAttribute(params string[] members) => Members = members; - /// - /// Gets field or property member names. - /// - public string[] Members { get; } + /// Gets field or property member names. + internal string[] Members { get; } } #else diff --git a/src/ReactiveUI.Binding/Polyfills/NotNullAttribute.cs b/src/ReactiveUI.Binding/Polyfills/NotNullAttribute.cs index 7711b94..8bb9aa6 100644 --- a/src/ReactiveUI.Binding/Polyfills/NotNullAttribute.cs +++ b/src/ReactiveUI.Binding/Polyfills/NotNullAttribute.cs @@ -9,16 +9,13 @@ namespace System.Diagnostics.CodeAnalysis; -/// -/// Specifies that an output is not even if the -/// corresponding type allows it. -/// +/// Specifies that an output is not even if the corresponding type allows it. [ExcludeFromCodeCoverage] [DebuggerNonUserCode] [AttributeUsage( - validOn: AttributeTargets.Field | - AttributeTargets.Parameter | - AttributeTargets.Property | - AttributeTargets.ReturnValue)] + validOn: AttributeTargets.Field + | AttributeTargets.Parameter + | AttributeTargets.Property + | AttributeTargets.ReturnValue)] internal sealed class NotNullAttribute : Attribute; #endif diff --git a/src/ReactiveUI.Binding/Polyfills/NotNullWhenAttribute.cs b/src/ReactiveUI.Binding/Polyfills/NotNullWhenAttribute.cs index 0971f61..68f57bb 100644 --- a/src/ReactiveUI.Binding/Polyfills/NotNullWhenAttribute.cs +++ b/src/ReactiveUI.Binding/Polyfills/NotNullWhenAttribute.cs @@ -9,18 +9,13 @@ namespace System.Diagnostics.CodeAnalysis; -/// -/// Specifies that when a method returns , -/// the parameter will not be even if the corresponding type allows it. -/// +/// Specifies that when a method returns , the parameter will not be even if the corresponding type allows it. [ExcludeFromCodeCoverage] [DebuggerNonUserCode] [AttributeUsage(AttributeTargets.Parameter)] internal sealed class NotNullWhenAttribute : Attribute { - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// /// The return value condition. If the method returns this value, /// the associated parameter will not be . @@ -32,7 +27,7 @@ public NotNullWhenAttribute(bool returnValue) => /// Gets a value indicating whether the return condition has been satisfied. /// If the method returns this value, the associated parameter will not be . /// - public bool ReturnValue { get; } + internal bool ReturnValue { get; } } #else diff --git a/src/ReactiveUI.Binding/Polyfills/Range.cs b/src/ReactiveUI.Binding/Polyfills/Range.cs new file mode 100644 index 0000000..ecf455a --- /dev/null +++ b/src/ReactiveUI.Binding/Polyfills/Range.cs @@ -0,0 +1,85 @@ +// Copyright (c) 2019-2026 ReactiveUI Association Incorporated. All rights reserved. +// ReactiveUI Association Incorporated licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +// Polyfill implementation adapted from SimonCropp/Polyfill +// https://github.com/SimonCropp/Polyfill +#if !NET +using System.Diagnostics.CodeAnalysis; + +namespace System; + +/// +/// Represents a range with a start and an end index. +/// Polyfill for the framework targets that predate System.Range, enabling the .. range operator. +/// +[ExcludeFromCodeCoverage] +internal readonly struct Range : IEquatable +{ + /// Initializes a new instance of the struct. + /// The inclusive start index of the range. + /// The exclusive end index of the range. + public Range(Index start, Index end) + { + Start = start; + End = end; + } + + /// Gets a that covers the entire collection. + internal static Range All => new(Index.Start, Index.End); + + /// Gets the inclusive start index of the range. + internal Index Start { get; } + + /// Gets the exclusive end index of the range. + internal Index End { get; } + + /// Determines whether two ranges are equal. + /// The first range. + /// The second range. + /// if the ranges are equal; otherwise . + public static bool operator ==(Range left, Range right) => left.Equals(right); + + /// Determines whether two ranges are not equal. + /// The first range. + /// The second range. + /// if the ranges are not equal; otherwise . + public static bool operator !=(Range left, Range right) => !left.Equals(right); + + /// + public bool Equals(Range other) => Start.Equals(other.Start) && End.Equals(other.End); + + /// + public override bool Equals(object? obj) => obj is Range other && Equals(other); + + /// + public override int GetHashCode() => Start.GetHashCode() ^ End.GetHashCode(); + + /// Creates a range that starts at the supplied index and runs to the end of the collection. + /// The inclusive start index. + /// The created . + internal static Range StartAt(Index start) => new(start, Index.End); + + /// Creates a range that starts at the beginning of the collection and ends at the supplied index. + /// The exclusive end index. + /// The created . + internal static Range EndAt(Index end) => new(Index.Start, end); + + /// Calculates the start offset and length of the range for a collection of the supplied length. + /// The length of the collection. + /// A tuple containing the start offset and the length of the range. + internal (int Offset, int Length) GetOffsetAndLength(int length) + { + var start = Start.GetOffset(length); + var end = End.GetOffset(length); + + if ((uint)end > (uint)length || (uint)start > (uint)end) + { + throw new ArgumentOutOfRangeException(nameof(length)); + } + + return (start, end - start); + } +} + +#endif diff --git a/src/ReactiveUI.Binding/Polyfills/RequiresDynamicCodeAttribute.cs b/src/ReactiveUI.Binding/Polyfills/RequiresDynamicCodeAttribute.cs index 7c9deca..3493828 100644 --- a/src/ReactiveUI.Binding/Polyfills/RequiresDynamicCodeAttribute.cs +++ b/src/ReactiveUI.Binding/Polyfills/RequiresDynamicCodeAttribute.cs @@ -11,42 +11,32 @@ namespace System.Diagnostics.CodeAnalysis; -/// -/// Indicates that the specified method requires the ability to generate new code at runtime, -/// for example through . -/// +/// Indicates that the specified method requires the ability to generate new code at runtime, for example through . [ExcludeFromCodeCoverage] [DebuggerNonUserCode] [AttributeUsage( - validOn: Targets.Method | - Targets.Constructor | - Targets.Class, + validOn: Targets.Method + | Targets.Constructor + | Targets.Class, Inherited = false)] internal sealed class RequiresDynamicCodeAttribute : Attribute { - /// - /// Initializes a new instance of the class - /// with the specified message. - /// + /// Initializes a new instance of the class with the specified message. /// A message that contains information about the usage of dynamic code. public RequiresDynamicCodeAttribute(string message) => Message = message; - /// - /// Gets or sets a value indicating whether the annotation should not apply to static members. - /// - public bool ExcludeStatics { get; set; } + /// Gets or sets a value indicating whether the annotation should not apply to static members. + internal bool ExcludeStatics { get; set; } - /// - /// Gets a message that contains information about the usage of dynamic code. - /// - public string Message { get; } + /// Gets a message that contains information about the usage of dynamic code. + internal string Message { get; } /// /// Gets or sets an optional URL that contains more information about the method, /// why it requires dynamic code, and what options a consumer has to deal with it. /// - public string? Url { get; set; } + internal string? Url { get; set; } } #else [assembly: TypeForwardedTo(typeof(RequiresDynamicCodeAttribute))] diff --git a/src/ReactiveUI.Binding/Polyfills/RequiresUnreferencedCodeAttribute.cs b/src/ReactiveUI.Binding/Polyfills/RequiresUnreferencedCodeAttribute.cs index 6c9d34a..61d1de1 100644 --- a/src/ReactiveUI.Binding/Polyfills/RequiresUnreferencedCodeAttribute.cs +++ b/src/ReactiveUI.Binding/Polyfills/RequiresUnreferencedCodeAttribute.cs @@ -16,30 +16,25 @@ namespace System.Diagnostics.CodeAnalysis; [ExcludeFromCodeCoverage] [DebuggerNonUserCode] [AttributeUsage( - AttributeTargets.Method | - AttributeTargets.Constructor | - AttributeTargets.Class, + AttributeTargets.Method + | AttributeTargets.Constructor + | AttributeTargets.Class, Inherited = false)] internal sealed class RequiresUnreferencedCodeAttribute : Attribute { - /// - /// Initializes a new instance of the class - /// with the specified message. - /// + /// Initializes a new instance of the class with the specified message. /// A message that contains information about the usage of unreferenced code. public RequiresUnreferencedCodeAttribute(string message) => Message = message; - /// - /// Gets a message that contains information about the usage of unreferenced code. - /// - public string Message { get; } + /// Gets a message that contains information about the usage of unreferenced code. + internal string Message { get; } /// /// Gets or sets an optional URL that contains more information about the method, /// why it requires unreferenced code, and what options a consumer has to deal with it. /// - public string? Url { get; set; } + internal string? Url { get; set; } } #else diff --git a/src/ReactiveUI.Binding/Polyfills/UnconditionalSuppressMessageAttribute.cs b/src/ReactiveUI.Binding/Polyfills/UnconditionalSuppressMessageAttribute.cs index ce1151d..eb782ce 100644 --- a/src/ReactiveUI.Binding/Polyfills/UnconditionalSuppressMessageAttribute.cs +++ b/src/ReactiveUI.Binding/Polyfills/UnconditionalSuppressMessageAttribute.cs @@ -9,10 +9,7 @@ namespace System.Diagnostics.CodeAnalysis; -/// -/// Suppresses reporting of a specific rule violation, allowing multiple suppressions on a -/// single code artifact. -/// +/// Suppresses reporting of a specific rule violation, allowing multiple suppressions on a single code artifact. [ExcludeFromCodeCoverage] [DebuggerNonUserCode] [AttributeUsage( @@ -21,10 +18,7 @@ namespace System.Diagnostics.CodeAnalysis; AllowMultiple = true)] internal sealed class UnconditionalSuppressMessageAttribute : Attribute { - /// - /// Initializes a new instance of the - /// class, specifying the category of the tool and the identifier for an analysis rule. - /// + /// Initializes a new instance of the class, specifying the category of the tool and the identifier for an analysis rule. /// The category identifying the classification of the attribute. /// The identifier of the analysis tool rule to be suppressed. public UnconditionalSuppressMessageAttribute(string category, string checkId) @@ -33,35 +27,23 @@ public UnconditionalSuppressMessageAttribute(string category, string checkId) CheckId = checkId; } - /// - /// Gets the category identifying the classification of the attribute. - /// - public string Category { get; } + /// Gets the category identifying the classification of the attribute. + internal string Category { get; } - /// - /// Gets the identifier of the analysis tool rule to be suppressed. - /// - public string CheckId { get; } + /// Gets the identifier of the analysis tool rule to be suppressed. + internal string CheckId { get; } - /// - /// Gets or sets the scope of the code that is relevant for the attribute. - /// - public string? Scope { get; set; } + /// Gets or sets the scope of the code that is relevant for the attribute. + internal string? Scope { get; set; } - /// - /// Gets or sets a fully qualified path that represents the target of the attribute. - /// - public string? Target { get; set; } + /// Gets or sets a fully qualified path that represents the target of the attribute. + internal string? Target { get; set; } - /// - /// Gets or sets an optional argument expanding on exclusion criteria. - /// - public string? MessageId { get; set; } + /// Gets or sets an optional argument expanding on exclusion criteria. + internal string? MessageId { get; set; } - /// - /// Gets or sets the justification for suppressing the code analysis message. - /// - public string? Justification { get; set; } + /// Gets or sets the justification for suppressing the code analysis message. + internal string? Justification { get; set; } } #else diff --git a/src/ReactiveUI.Binding/ReactiveUI.Binding.csproj b/src/ReactiveUI.Binding/ReactiveUI.Binding.csproj index eaee09c..38d1bfc 100644 --- a/src/ReactiveUI.Binding/ReactiveUI.Binding.csproj +++ b/src/ReactiveUI.Binding/ReactiveUI.Binding.csproj @@ -25,6 +25,27 @@ - + + + + + + + + + + + + + + + + + + diff --git a/src/ReactiveUI.Binding/View/DefaultViewLocator.cs b/src/ReactiveUI.Binding/View/DefaultViewLocator.cs index f6dbb93..2389ef6 100644 --- a/src/ReactiveUI.Binding/View/DefaultViewLocator.cs +++ b/src/ReactiveUI.Binding/View/DefaultViewLocator.cs @@ -11,10 +11,6 @@ namespace ReactiveUI.Binding; /// using a three-tier resolution strategy: source-generated AOT-safe dispatch, explicit runtime /// mappings, and service locator fallback. /// -[SuppressMessage( - "Major Code Smell", - "S4018:Generic methods should provide type parameter for type inference", - Justification = "The type parameter denotes the target type (value/control/view), supplied explicitly by callers; it is not derivable from the arguments. Public API.")] public sealed class DefaultViewLocator : IViewLocator { /// @@ -23,14 +19,8 @@ public sealed class DefaultViewLocator : IViewLocator /// private static Func? _generatedDispatch; - /// - /// Synchronization lock for thread-safe access to this instance's mappings. - /// -#if NET9_0_OR_GREATER + /// Synchronization lock for thread-safe access to this instance's mappings. private readonly Lock _lock = new(); -#else - private readonly object _lock = new(); -#endif /// /// Runtime explicit mappings from (viewModelType, contract) to view factory. @@ -50,21 +40,19 @@ public static void SetGeneratedViewDispatch(Func disp _generatedDispatch = dispatch; } - /// - /// Registers an explicit view mapping for a view model type. - /// + /// Registers an explicit view mapping for a view model type. /// The view model type. /// The view type. Must implement . + [SuppressMessage("Design", "SST2307:Type parameters should be inferable", Justification = "Specified explicitly by the caller; it identifies the mapping.")] public void Map() where TViewModel : class where TView : IViewFor, new() => Map(null); - /// - /// Registers an explicit view mapping for a view model type. - /// + /// Registers an explicit view mapping for a view model type. /// The view model type. /// The view type. Must implement . /// A contract string for named registrations. + [SuppressMessage("Design", "SST2307:Type parameters should be inferable", Justification = "Specified explicitly by the caller; it identifies the mapping.")] public void Map(string? contract) where TViewModel : class where TView : IViewFor, new() @@ -76,20 +64,18 @@ public void Map(string? contract) } } - /// - /// Registers an explicit view mapping with a custom factory for a view model type. - /// + /// Registers an explicit view mapping with a custom factory for a view model type. /// The view model type. /// A factory function that creates the view. + [SuppressMessage("Design", "SST2307:Type parameters should be inferable", Justification = "Specified explicitly by the caller; it identifies the mapping.")] public void Map(Func factory) where TViewModel : class => Map(factory, null); - /// - /// Registers an explicit view mapping with a custom factory for a view model type. - /// + /// Registers an explicit view mapping with a custom factory for a view model type. /// The view model type. /// A factory function that creates the view. /// A contract string for named registrations. + [SuppressMessage("Design", "SST2307:Type parameters should be inferable", Justification = "Specified explicitly by the caller; it identifies the mapping.")] public void Map(Func factory, string? contract) where TViewModel : class { @@ -102,20 +88,18 @@ public void Map(Func factory, string? contract) } } - /// - /// Removes an explicit view mapping for a view model type. - /// + /// Removes an explicit view mapping for a view model type. /// The view model type. /// if the mapping was removed; otherwise, . + [SuppressMessage("Design", "SST2307:Type parameters should be inferable", Justification = "Specified explicitly by the caller; it identifies the mapping.")] public bool Unmap() where TViewModel : class => Unmap(null); - /// - /// Removes an explicit view mapping for a view model type. - /// + /// Removes an explicit view mapping for a view model type. /// The view model type. /// A contract string for named registrations. /// if the mapping was removed; otherwise, . + [SuppressMessage("Design", "SST2307:Type parameters should be inferable", Justification = "Specified explicitly by the caller; it identifies the mapping.")] public bool Unmap(string? contract) where TViewModel : class { @@ -206,28 +190,20 @@ public bool Unmap(string? contract) return TryResolveViaReflection(viewModel, normalizedContract); } - /// - /// Creates a new for fluent registration of view-to-view-model mappings. - /// + /// Creates a new for fluent registration of view-to-view-model mappings. /// A new targeting this locator instance. public ViewMappingBuilder CreateMappingBuilder() => new(this); - /// - /// Resets the generated view dispatch for testing purposes. - /// + /// Resets the generated view dispatch for testing purposes. [EditorBrowsable(EditorBrowsableState.Never)] internal static void ResetGeneratedViewDispatchForTesting() => _generatedDispatch = null; - /// - /// Sets the view model on the resolved view. - /// + /// Sets the view model on the resolved view. /// The view to set the view model on. /// The view model instance. private static void SetViewModelOnView(IViewFor view, object viewModel) => view.ViewModel = viewModel; - /// - /// Fallback resolution using MakeGenericType. Not AOT-safe but provides backward compatibility. - /// + /// Fallback resolution using MakeGenericType. Not AOT-safe but provides backward compatibility. /// The view model instance. /// The normalized contract string. /// The resolved view, or . @@ -236,8 +212,8 @@ public bool Unmap(string? contract) { try { - var vmType = viewModel.GetType(); - var viewForType = typeof(IViewFor<>).MakeGenericType(vmType); + var viewModelType = viewModel.GetType(); + var viewForType = typeof(IViewFor<>).MakeGenericType(viewModelType); var svcContract = contract.Length == 0 ? null : contract; var view = AppLocator.Current.GetService(viewForType, svcContract) as IViewFor; if (view is not null) @@ -246,28 +222,22 @@ public bool Unmap(string? contract) return view; } } - catch + catch (Exception ex) when (ex is InvalidOperationException or NotSupportedException or TypeLoadException or ArgumentException) { - // MakeGenericType can fail on AOT platforms — this is expected + // MakeGenericType cannot build the closed IViewFor<> on AOT platforms where the + // instantiation was trimmed; the caller falls back to the other resolution tiers. } return null; } - /// - /// Tries to resolve a view from the explicit runtime mappings dictionary. - /// + /// Tries to resolve a view from the explicit runtime mappings dictionary. /// The type of the view model. /// The normalized contract string. /// The resolved view, or . private IViewFor? TryResolveFromMappings(Type viewModelType, string contract) { var mappings = _mappings; - if (!mappings.TryGetValue((viewModelType, contract), out var factory)) - { - return null; - } - - return factory(); + return !mappings.TryGetValue((viewModelType, contract), out var factory) ? null : factory(); } } diff --git a/src/ReactiveUI.Binding/View/ViewContractAttribute.cs b/src/ReactiveUI.Binding/View/ViewContractAttribute.cs index bec3234..78973d5 100644 --- a/src/ReactiveUI.Binding/View/ViewContractAttribute.cs +++ b/src/ReactiveUI.Binding/View/ViewContractAttribute.cs @@ -14,8 +14,6 @@ namespace ReactiveUI.Binding; [AttributeUsage(AttributeTargets.Class)] public sealed class ViewContractAttribute(string contract) : Attribute { - /// - /// Gets the contract to use when resolving the view. - /// + /// Gets the contract to use when resolving the view. public string Contract { get; } = contract; } diff --git a/src/ReactiveUI.Binding/View/ViewLocator.cs b/src/ReactiveUI.Binding/View/ViewLocator.cs index b958362..b107832 100644 --- a/src/ReactiveUI.Binding/View/ViewLocator.cs +++ b/src/ReactiveUI.Binding/View/ViewLocator.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding; -/// -/// Static accessor for the current instance. -/// +/// Static accessor for the current instance. public static class ViewLocator { - /// - /// Gets the current from the service locator. - /// + /// Gets the current from the service locator. /// The current instance. /// /// Thrown when no is registered. diff --git a/src/ReactiveUI.Binding/View/ViewLocatorNotFoundException.cs b/src/ReactiveUI.Binding/View/ViewLocatorNotFoundException.cs index f8e0b40..8e9b1ef 100644 --- a/src/ReactiveUI.Binding/View/ViewLocatorNotFoundException.cs +++ b/src/ReactiveUI.Binding/View/ViewLocatorNotFoundException.cs @@ -4,37 +4,27 @@ namespace ReactiveUI.Binding; -/// -/// Exception thrown when a view locator is not registered with the dependency resolver. -/// +/// Exception thrown when a view locator is not registered with the dependency resolver. #if !NET8_0_OR_GREATER [Serializable] #endif public class ViewLocatorNotFoundException : Exception { - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. public ViewLocatorNotFoundException() : base( "No IViewLocator is registered. Call RxBindingBuilder.CreateReactiveUIBindingBuilder().WithCoreServices().BuildApp() to register default services.") { } - /// - /// Initializes a new instance of the class - /// with a specified error message. - /// + /// Initializes a new instance of the class with a specified error message. /// The message that describes the error. public ViewLocatorNotFoundException(string message) : base(message) { } - /// - /// Initializes a new instance of the class - /// with a specified error message and a reference to the inner exception. - /// + /// Initializes a new instance of the class with a specified error message and a reference to the inner exception. /// The message that describes the error. /// The exception that is the cause of the current exception. public ViewLocatorNotFoundException(string message, Exception innerException) diff --git a/src/ReactiveUI.Binding/View/ViewMappingBuilder.cs b/src/ReactiveUI.Binding/View/ViewMappingBuilder.cs index 8f15c93..4d1f40a 100644 --- a/src/ReactiveUI.Binding/View/ViewMappingBuilder.cs +++ b/src/ReactiveUI.Binding/View/ViewMappingBuilder.cs @@ -4,43 +4,31 @@ namespace ReactiveUI.Binding; -/// -/// Fluent builder for registering view-to-view-model mappings on a . -/// -[SuppressMessage( - "Major Code Smell", - "S4018:Generic methods should provide type parameter for type inference", - Justification = "The type parameter denotes the target type (value/control/view), supplied explicitly by callers; it is not derivable from the arguments. Public API.")] +/// Fluent builder for registering view-to-view-model mappings on a . public sealed class ViewMappingBuilder { - /// - /// The view locator to register mappings on. - /// + /// The view locator to register mappings on. private readonly DefaultViewLocator _locator; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The view locator to register mappings on. internal ViewMappingBuilder(DefaultViewLocator locator) => _locator = locator; - /// - /// Maps a view model type to a view type with direct construction. - /// + /// Maps a view model type to a view type with direct construction. /// The view model type. /// The view type. Must have a parameterless constructor. /// This builder for chaining. + [SuppressMessage("Design", "SST2307:Type parameters should be inferable", Justification = "Specified explicitly by the caller; it identifies the mapping.")] public ViewMappingBuilder Map() where TViewModel : class where TView : IViewFor, new() => Map(null); - /// - /// Maps a view model type to a view type with direct construction. - /// + /// Maps a view model type to a view type with direct construction. /// The view model type. /// The view type. Must have a parameterless constructor. /// A contract string for named registrations. /// This builder for chaining. + [SuppressMessage("Design", "SST2307:Type parameters should be inferable", Justification = "Specified explicitly by the caller; it identifies the mapping.")] public ViewMappingBuilder Map(string? contract) where TViewModel : class where TView : IViewFor, new() @@ -49,22 +37,20 @@ public ViewMappingBuilder Map(string? contract) return this; } - /// - /// Maps a view model type to a view using a custom factory function. - /// + /// Maps a view model type to a view using a custom factory function. /// The view model type. /// A factory function that creates the view. /// This builder for chaining. + [SuppressMessage("Design", "SST2307:Type parameters should be inferable", Justification = "Specified explicitly by the caller; it identifies the mapping.")] public ViewMappingBuilder Map(Func factory) where TViewModel : class => Map(factory, null); - /// - /// Maps a view model type to a view using a custom factory function. - /// + /// Maps a view model type to a view using a custom factory function. /// The view model type. /// A factory function that creates the view. /// A contract string for named registrations. /// This builder for chaining. + [SuppressMessage("Design", "SST2307:Type parameters should be inferable", Justification = "Specified explicitly by the caller; it identifies the mapping.")] public ViewMappingBuilder Map(Func factory, string? contract) where TViewModel : class { diff --git a/src/benchmarks/ReactiveUI.Binding.Benchmarks.ReactiveUI/ModuleInitializer.cs b/src/benchmarks/ReactiveUI.Binding.Benchmarks.ReactiveUI/ModuleInitializer.cs index 2c8e257..94ca105 100644 --- a/src/benchmarks/ReactiveUI.Binding.Benchmarks.ReactiveUI/ModuleInitializer.cs +++ b/src/benchmarks/ReactiveUI.Binding.Benchmarks.ReactiveUI/ModuleInitializer.cs @@ -13,15 +13,10 @@ namespace ReactiveUI.Binding.Benchmarks; /// internal static class ModuleInitializer { - /// - /// Guard flag to ensure initialization runs at most once. Uses . - /// + /// Guard flag to ensure initialization runs at most once. Uses . private static int _initialized; - /// - /// Ensures ReactiveUI is initialized exactly once, regardless of how many - /// benchmark classes call this method. - /// + /// Ensures ReactiveUI is initialized exactly once, regardless of how many benchmark classes call this method. internal static void EnsureInitialized() { if (Interlocked.Exchange(ref _initialized, 1) != 0) @@ -30,14 +25,12 @@ internal static void EnsureInitialized() } ModeDetector.OverrideModeDetector(new BenchmarkModeDetector()); - RxAppBuilder.CreateReactiveUIBuilder() + _ = RxAppBuilder.CreateReactiveUIBuilder() .WithCoreServices() .BuildApp(); } - /// - /// Mode detector for benchmark context. - /// + /// Mode detector for benchmark context. private sealed class BenchmarkModeDetector : IModeDetector { /// diff --git a/src/benchmarks/ReactiveUI.Binding.Benchmarks.ReactiveUI/Program.cs b/src/benchmarks/ReactiveUI.Binding.Benchmarks.ReactiveUI/Program.cs index 5636958..bd28557 100644 --- a/src/benchmarks/ReactiveUI.Binding.Benchmarks.ReactiveUI/Program.cs +++ b/src/benchmarks/ReactiveUI.Binding.Benchmarks.ReactiveUI/Program.cs @@ -4,4 +4,13 @@ using BenchmarkDotNet.Running; -BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); +namespace ReactiveUI.Binding.Benchmarks.ReactiveUI; + +/// Entry point for the ReactiveUI comparison benchmarks. +internal static class Program +{ + /// Runs the benchmarks selected by . + /// The command line arguments passed to the benchmark switcher. + internal static void Main(string[] args) => + _ = BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); +} diff --git a/src/benchmarks/ReactiveUI.Binding.Benchmarks.ReactiveUI/ReactiveUIBindingBenchmark.cs b/src/benchmarks/ReactiveUI.Binding.Benchmarks.ReactiveUI/ReactiveUIBindingBenchmark.cs index db57913..1ba2d47 100644 --- a/src/benchmarks/ReactiveUI.Binding.Benchmarks.ReactiveUI/ReactiveUIBindingBenchmark.cs +++ b/src/benchmarks/ReactiveUI.Binding.Benchmarks.ReactiveUI/ReactiveUIBindingBenchmark.cs @@ -7,40 +7,26 @@ namespace ReactiveUI.Binding.Benchmarks; -/// -/// ReactiveUI expression-tree binding benchmarks for comparison. -/// -////[SimpleJob(RuntimeMoniker.Net462)] +/// ReactiveUI expression-tree binding benchmarks for comparison. [SimpleJob(RuntimeMoniker.Net80)] [SimpleJob(RuntimeMoniker.Net10_0)] [MemoryDiagnoser] [MarkdownExporterAttribute.GitHub] public class ReactiveUIBindingBenchmark { - /// - /// The number of property changes to fire during each benchmark iteration. - /// + /// The number of property changes to fire during each benchmark iteration. private const int PropertyChangeCount = 1_000; - /// - /// The source view model instance used for binding benchmarks. - /// + /// The source view model instance used for binding benchmarks. private BenchmarkViewModel _source = null!; - /// - /// The target view instance used for binding benchmarks. - /// + /// The target view instance used for binding benchmarks. private BenchmarkView _target = null!; - /// - /// Initializes static members of the class. - /// Ensures ReactiveUI is configured before any benchmarks run. - /// + /// Initializes static members of the class. Ensures ReactiveUI is configured before any benchmarks run. static ReactiveUIBindingBenchmark() => ModuleInitializer.EnsureInitialized(); - /// - /// Sets up fresh source and target objects before each benchmark iteration. - /// + /// Sets up fresh source and target objects before each benchmark iteration. [IterationSetup] public void Setup() { @@ -48,9 +34,7 @@ public void Setup() _target = new() { ViewModel = _source }; } - /// - /// Expression-tree one-way binding: setup, fire N changes, dispose. - /// + /// Expression-tree one-way binding: setup, fire N changes, dispose. [Benchmark(Description = "OneWayBind")] public void OneWayBind() { @@ -62,9 +46,7 @@ public void OneWayBind() } } - /// - /// Expression-tree two-way binding: setup, fire N source changes, dispose. - /// + /// Expression-tree two-way binding: setup, fire N source changes, dispose. [Benchmark(Description = "Bind")] public void Bind() { @@ -76,18 +58,14 @@ public void Bind() } } - /// - /// Cold start: create one-way binding, dispose immediately. - /// + /// Cold start: create one-way binding, dispose immediately. [Benchmark(Description = "First OneWayBind")] public void FirstOneWayBind() { using var binding = _target.OneWayBind(_source, x => x.Name, x => x.DisplayName); } - /// - /// Cold start: create two-way binding, dispose immediately. - /// + /// Cold start: create two-way binding, dispose immediately. [Benchmark(Description = "First Bind")] public void FirstBind() { diff --git a/src/benchmarks/ReactiveUI.Binding.Benchmarks.ReactiveUI/ReactiveUIObservationBenchmark.cs b/src/benchmarks/ReactiveUI.Binding.Benchmarks.ReactiveUI/ReactiveUIObservationBenchmark.cs index 9c68ebf..f799352 100644 --- a/src/benchmarks/ReactiveUI.Binding.Benchmarks.ReactiveUI/ReactiveUIObservationBenchmark.cs +++ b/src/benchmarks/ReactiveUI.Binding.Benchmarks.ReactiveUI/ReactiveUIObservationBenchmark.cs @@ -7,42 +7,28 @@ namespace ReactiveUI.Binding.Benchmarks; -/// -/// ReactiveUI expression-tree WhenAnyValue benchmarks for comparison. -/// -////[SimpleJob(RuntimeMoniker.Net462)] +/// ReactiveUI expression-tree WhenAnyValue benchmarks for comparison. [SimpleJob(RuntimeMoniker.Net80)] [SimpleJob(RuntimeMoniker.Net10_0)] [MemoryDiagnoser] [MarkdownExporterAttribute.GitHub] public class ReactiveUIObservationBenchmark { - /// - /// The number of property changes to fire during each benchmark iteration. - /// + /// The number of property changes to fire during each benchmark iteration. private const int PropertyChangeCount = 1_000; - /// - /// The view model instance used for observation benchmarks. - /// + /// The view model instance used for observation benchmarks. private BenchmarkViewModel _vm = null!; - /// - /// Initializes static members of the class. - /// Ensures ReactiveUI is configured before any benchmarks run. - /// + /// Initializes static members of the class. Ensures ReactiveUI is configured before any benchmarks run. static ReactiveUIObservationBenchmark() => ModuleInitializer.EnsureInitialized(); - /// - /// Sets up a fresh view model before each benchmark iteration. - /// + /// Sets up a fresh view model before each benchmark iteration. [IterationSetup] public void Setup() => _vm = new() { Name = "Initial", Age = 0, Child = new() { Value = "ChildInitial" } }; - /// - /// Expression-tree single property observation: subscribe, fire N changes, dispose. - /// + /// Expression-tree single property observation: subscribe, fire N changes, dispose. [Benchmark(Description = "Single Property")] public void SingleProperty() { @@ -56,9 +42,7 @@ public void SingleProperty() } } - /// - /// Expression-tree deep chain observation: subscribe, fire N changes, dispose. - /// + /// Expression-tree deep chain observation: subscribe, fire N changes, dispose. [Benchmark(Description = "Deep Chain")] public void DeepChain() { @@ -72,14 +56,12 @@ public void DeepChain() } } - /// - /// Expression-tree multi-property observation: subscribe, fire N changes, dispose. - /// + /// Expression-tree multi-property observation: subscribe, fire N changes, dispose. [Benchmark(Description = "Two Properties")] public void TwoProperties() { (string name, int age) last = default; - using var sub = _vm.WhenAnyValue(x => x.Name, x => x.Age, (name, age) => (name, age)) + using var sub = _vm.WhenAnyValue(x => x.Name, x => x.Age, static (name, age) => (name, age)) .Subscribe(v => last = v); for (var i = 0; i < PropertyChangeCount; i++) @@ -89,9 +71,7 @@ public void TwoProperties() } } - /// - /// Cold start: subscribe, read initial value, dispose. Includes expression compilation overhead. - /// + /// Cold start: subscribe, read initial value, dispose. Includes expression compilation overhead. /// The observed value. [Benchmark(Description = "First Observation")] public string FirstObservation() diff --git a/src/benchmarks/ReactiveUI.Binding.Benchmarks/BenchmarkChildViewModel.cs b/src/benchmarks/ReactiveUI.Binding.Benchmarks/BenchmarkChildViewModel.cs index 292577d..e471e42 100644 --- a/src/benchmarks/ReactiveUI.Binding.Benchmarks/BenchmarkChildViewModel.cs +++ b/src/benchmarks/ReactiveUI.Binding.Benchmarks/BenchmarkChildViewModel.cs @@ -6,34 +6,25 @@ namespace ReactiveUI.Binding.Benchmarks; -/// -/// A child view model for deep chain benchmarks. -/// +/// A child view model for deep chain benchmarks. public class BenchmarkChildViewModel : INotifyPropertyChanged { - /// - /// The backing field for the property. - /// - private string _value = string.Empty; - /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the value. - /// + /// Gets or sets the value. public string Value { - get => _value; + get => field; set { - if (_value == value) + if (field == value) { return; } - _value = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Value))); } - } + } = string.Empty; } diff --git a/src/benchmarks/ReactiveUI.Binding.Benchmarks/BenchmarkView.cs b/src/benchmarks/ReactiveUI.Binding.Benchmarks/BenchmarkView.cs index 096bc2c..9564127 100644 --- a/src/benchmarks/ReactiveUI.Binding.Benchmarks/BenchmarkView.cs +++ b/src/benchmarks/ReactiveUI.Binding.Benchmarks/BenchmarkView.cs @@ -6,62 +6,40 @@ namespace ReactiveUI.Binding.Benchmarks; -/// -/// A view used for binding benchmarks. -/// Implements to support ReactiveUI's expression-tree-based binding APIs. -/// +/// A view used for binding benchmarks. Implements to support ReactiveUI's expression-tree-based binding APIs. public class BenchmarkView : IViewFor, INotifyPropertyChanged { - /// - /// The backing field for the property. - /// - private string _displayName = string.Empty; - - /// - /// The backing field for the property. - /// - private int _displayAge; - - /// - /// The backing field for the property. - /// - private BenchmarkViewModel? _viewModel; - /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the display name. - /// + /// Gets or sets the display name. public string DisplayName { - get => _displayName; + get => field; set { - if (_displayName == value) + if (field == value) { return; } - _displayName = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(DisplayName))); } - } + } = string.Empty; - /// - /// Gets or sets the display age. - /// + /// Gets or sets the display age. public int DisplayAge { - get => _displayAge; + get => field; set { - if (_displayAge == value) + if (field == value) { return; } - _displayAge = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(DisplayAge))); } } @@ -69,15 +47,15 @@ public int DisplayAge /// public BenchmarkViewModel? ViewModel { - get => _viewModel; + get => field; set { - if (_viewModel == value) + if (field == value) { return; } - _viewModel = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(ViewModel))); } } diff --git a/src/benchmarks/ReactiveUI.Binding.Benchmarks/BenchmarkViewModel.cs b/src/benchmarks/ReactiveUI.Binding.Benchmarks/BenchmarkViewModel.cs index 3d360b0..cc500d9 100644 --- a/src/benchmarks/ReactiveUI.Binding.Benchmarks/BenchmarkViewModel.cs +++ b/src/benchmarks/ReactiveUI.Binding.Benchmarks/BenchmarkViewModel.cs @@ -6,86 +6,63 @@ namespace ReactiveUI.Binding.Benchmarks; -/// -/// A view model used for benchmarking source-generated property observation and binding. -/// +/// A view model used for benchmarking source-generated property observation and binding. public class BenchmarkViewModel : INotifyPropertyChanged, INotifyPropertyChanging { - /// - /// The backing field for the property. - /// - private string _name = string.Empty; - - /// - /// The backing field for the property. - /// - private int _age; - - /// - /// The backing field for the property. - /// - private BenchmarkChildViewModel _child = new(); - /// public event PropertyChangedEventHandler? PropertyChanged; /// public event PropertyChangingEventHandler? PropertyChanging; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { - get => _name; + get => field; set { - if (_name == value) + if (field == value) { return; } PropertyChanging?.Invoke(this, new(nameof(Name))); - _name = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Name))); } - } + } = string.Empty; - /// - /// Gets or sets the age. - /// + /// Gets or sets the age. public int Age { - get => _age; + get => field; set { - if (_age == value) + if (field == value) { return; } PropertyChanging?.Invoke(this, new(nameof(Age))); - _age = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Age))); } } - /// - /// Gets or sets the child view model. - /// + /// Gets or sets the child view model. public BenchmarkChildViewModel Child { - get => _child; + get => field; set { - if (_child == value) + if (field == value) { return; } PropertyChanging?.Invoke(this, new(nameof(Child))); - _child = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Child))); } - } + } = new(); } diff --git a/src/benchmarks/ReactiveUI.Binding.Benchmarks/BindOneWayBenchmark.cs b/src/benchmarks/ReactiveUI.Binding.Benchmarks/BindOneWayBenchmark.cs index f2938cb..97149ff 100644 --- a/src/benchmarks/ReactiveUI.Binding.Benchmarks/BindOneWayBenchmark.cs +++ b/src/benchmarks/ReactiveUI.Binding.Benchmarks/BindOneWayBenchmark.cs @@ -8,10 +8,7 @@ namespace ReactiveUI.Binding.Benchmarks; -/// -/// Source-generated BindOneWay benchmarks with and without scheduler. -/// -////[SimpleJob(RuntimeMoniker.Net462)] +/// Source-generated BindOneWay benchmarks with and without scheduler. [SimpleJob(RuntimeMoniker.Net80)] [SimpleJob(RuntimeMoniker.Net10_0)] [SimpleJob(RuntimeMoniker.NativeAot10_0, id: nameof(RuntimeMoniker.NativeAot10_0))] @@ -19,29 +16,19 @@ namespace ReactiveUI.Binding.Benchmarks; [MarkdownExporterAttribute.GitHub] public class BindOneWayBenchmark { - /// - /// Represents the number of property change events to be triggered during the benchmark tests. - /// + /// Represents the number of property change events to be triggered during the benchmark tests. private const int PropertyChangeCount = 1_000; - /// - /// The number of consecutive bindings created in the setup/teardown benchmark. - /// + /// The number of consecutive bindings created in the setup/teardown benchmark. private const int BindingCount = 10; - /// - /// The source view model of the benchmark. - /// + /// The source view model of the benchmark. private BenchmarkViewModel _source = null!; - /// - /// The target view of the benchmark. - /// + /// The target view of the benchmark. private BenchmarkView _target = null!; - /// - /// Sets up fresh source and target objects before each benchmark iteration. - /// + /// Sets up fresh source and target objects before each benchmark iteration. [IterationSetup] public void Setup() { @@ -49,9 +36,7 @@ public void Setup() _target = new(); } - /// - /// One-way binding without scheduler: setup, fire N changes, dispose. - /// + /// One-way binding without scheduler: setup, fire N changes, dispose. [Benchmark(Description = "BindOneWay")] public void Standard() { @@ -63,9 +48,7 @@ public void Standard() } } - /// - /// One-way binding with ImmediateScheduler: measures ObserveOnObservable overhead. - /// + /// One-way binding with ImmediateScheduler: measures ObserveOnObservable overhead. [Benchmark(Description = "BindOneWay + Scheduler")] public void WithScheduler() { @@ -77,18 +60,14 @@ public void WithScheduler() } } - /// - /// Cold start: create binding, dispose immediately. No property changes. - /// + /// Cold start: create binding, dispose immediately. No property changes. [Benchmark(Description = "First Binding")] public void FirstBinding() { using var binding = _source.BindOneWay(_target, x => x.Name, x => x.DisplayName); } - /// - /// Setup and teardown cost of 10 consecutive bindings. - /// + /// Setup and teardown cost of 10 consecutive bindings. [Benchmark(Description = "10x Setup/Teardown")] public void SetupTeardown() { diff --git a/src/benchmarks/ReactiveUI.Binding.Benchmarks/BindTwoWayBenchmark.cs b/src/benchmarks/ReactiveUI.Binding.Benchmarks/BindTwoWayBenchmark.cs index 0c9b8fe..6ef6c68 100644 --- a/src/benchmarks/ReactiveUI.Binding.Benchmarks/BindTwoWayBenchmark.cs +++ b/src/benchmarks/ReactiveUI.Binding.Benchmarks/BindTwoWayBenchmark.cs @@ -8,10 +8,7 @@ namespace ReactiveUI.Binding.Benchmarks; -/// -/// Source-generated BindTwoWay benchmarks with and without scheduler. -/// -////[SimpleJob(RuntimeMoniker.Net462)] +/// Source-generated BindTwoWay benchmarks with and without scheduler. [SimpleJob(RuntimeMoniker.Net80)] [SimpleJob(RuntimeMoniker.Net10_0)] [SimpleJob(RuntimeMoniker.NativeAot10_0, id: nameof(RuntimeMoniker.NativeAot10_0))] @@ -19,29 +16,19 @@ namespace ReactiveUI.Binding.Benchmarks; [MarkdownExporterAttribute.GitHub] public class BindTwoWayBenchmark { - /// - /// Represents the number of property change events to be triggered during the benchmark tests. - /// + /// Represents the number of property change events to be triggered during the benchmark tests. private const int PropertyChangeCount = 1_000; - /// - /// The modulus used to alternate updates between the source and the target each iteration. - /// + /// The modulus used to alternate updates between the source and the target each iteration. private const int AlternationModulus = 2; - /// - /// The source and target view models used for binding benchmarks. - /// + /// The source and target view models used for binding benchmarks. private BenchmarkViewModel _source = null!; - /// - /// The target view used for binding benchmarks. - /// + /// The target view used for binding benchmarks. private BenchmarkView _target = null!; - /// - /// Sets up fresh source and target objects before each benchmark iteration. - /// + /// Sets up fresh source and target objects before each benchmark iteration. [IterationSetup] public void Setup() { @@ -49,9 +36,7 @@ public void Setup() _target = new(); } - /// - /// Two-way binding without scheduler: setup, fire N source changes, dispose. - /// + /// Two-way binding without scheduler: setup, fire N source changes, dispose. [Benchmark(Description = "BindTwoWay")] public void Standard() { @@ -63,9 +48,7 @@ public void Standard() } } - /// - /// Two-way binding with ImmediateScheduler: measures ObserveOnObservable overhead on both directions. - /// + /// Two-way binding with ImmediateScheduler: measures ObserveOnObservable overhead on both directions. [Benchmark(Description = "BindTwoWay + Scheduler")] public void WithScheduler() { @@ -77,9 +60,7 @@ public void WithScheduler() } } - /// - /// Two-way binding with alternating source and target changes. - /// + /// Two-way binding with alternating source and target changes. [Benchmark(Description = "Bidirectional")] public void Bidirectional() { @@ -105,6 +86,6 @@ public void Bidirectional() /// /// The instance of whose property changes are observed. /// An observable sequence of values that represent the changes to the property. - internal static IObservable TriggerViewGeneration(BenchmarkView view) - => view.WhenChanged(x => x.DisplayName); + internal static IObservable TriggerViewGeneration(BenchmarkView view) => + view.WhenChanged(x => x.DisplayName); } diff --git a/src/benchmarks/ReactiveUI.Binding.Benchmarks/Program.cs b/src/benchmarks/ReactiveUI.Binding.Benchmarks/Program.cs index 5636958..8f76c1d 100644 --- a/src/benchmarks/ReactiveUI.Binding.Benchmarks/Program.cs +++ b/src/benchmarks/ReactiveUI.Binding.Benchmarks/Program.cs @@ -4,4 +4,13 @@ using BenchmarkDotNet.Running; -BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); +namespace ReactiveUI.Binding.Benchmarks; + +/// Entry point that hands the command line to the BenchmarkDotNet switcher. +internal static class Program +{ + /// Runs the benchmark selected by the command line. + /// The command-line arguments passed to the switcher. + internal static void Main(string[] args) => + _ = BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); +} diff --git a/src/benchmarks/ReactiveUI.Binding.Benchmarks/WhenChangedBenchmark.cs b/src/benchmarks/ReactiveUI.Binding.Benchmarks/WhenChangedBenchmark.cs index af0ca79..6a3f6f0 100644 --- a/src/benchmarks/ReactiveUI.Binding.Benchmarks/WhenChangedBenchmark.cs +++ b/src/benchmarks/ReactiveUI.Binding.Benchmarks/WhenChangedBenchmark.cs @@ -7,10 +7,7 @@ namespace ReactiveUI.Binding.Benchmarks; -/// -/// Source-generated WhenChanged benchmarks using lightweight observables. -/// -////[SimpleJob(RuntimeMoniker.Net462)] +/// Source-generated WhenChanged benchmarks using lightweight observables. [SimpleJob(RuntimeMoniker.Net80)] [SimpleJob(RuntimeMoniker.Net10_0)] [SimpleJob(RuntimeMoniker.NativeAot10_0, id: nameof(RuntimeMoniker.NativeAot10_0))] @@ -18,26 +15,18 @@ namespace ReactiveUI.Binding.Benchmarks; [MarkdownExporterAttribute.GitHub] public class WhenChangedBenchmark { - /// - /// Represents the number of property change events to be triggered during the benchmark tests. - /// + /// Represents the number of property change events to be triggered during the benchmark tests. private const int PropertyChangeCount = 1_000; - /// - /// The view model instance used for observation benchmarks. - /// + /// The view model instance used for observation benchmarks. private BenchmarkViewModel _vm = null!; - /// - /// Sets up a fresh view model before each benchmark iteration. - /// + /// Sets up a fresh view model before each benchmark iteration. [IterationSetup] public void Setup() => _vm = new() { Name = "Initial", Age = 0, Child = new() { Value = "ChildInitial" } }; - /// - /// Single property observation: subscribe, fire N changes, dispose. - /// + /// Single property observation: subscribe, fire N changes, dispose. [Benchmark(Description = "Single Property")] public void SingleProperty() { @@ -51,9 +40,7 @@ public void SingleProperty() } } - /// - /// Deep chain observation: subscribe, fire N changes on nested property, dispose. - /// + /// Deep chain observation: subscribe, fire N changes on nested property, dispose. [Benchmark(Description = "Deep Chain")] public void DeepChain() { @@ -67,9 +54,7 @@ public void DeepChain() } } - /// - /// Multi-property observation with CombineLatest: subscribe, fire N changes, dispose. - /// + /// Multi-property observation with CombineLatest: subscribe, fire N changes, dispose. [Benchmark(Description = "Two Properties")] public void TwoProperties() { @@ -84,9 +69,7 @@ public void TwoProperties() } } - /// - /// Cold start: subscribe, read initial value, dispose. No property changes. - /// + /// Cold start: subscribe, read initial value, dispose. No property changes. /// The observed value. [Benchmark(Description = "First Observation")] public string FirstObservation() diff --git a/src/stylecop.json b/src/stylecop.json deleted file mode 100644 index 00e1a08..0000000 --- a/src/stylecop.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", - "settings": { - "indentation": { - "useTabs": false, - "indentationSize": 4 - }, - "documentationRules": { - "documentExposedElements": true, - "documentInternalElements": true, - "documentPrivateElements": true, - "documentInterfaces": true, - "documentPrivateFields": true, - "documentationCulture": "en-US", - "companyName": "ReactiveUI Association Incorporated", - "copyrightText": "Copyright (c) 2019-2026 {companyName}. All rights reserved.\n{companyName} licenses this file to you under the {licenseName} license.\nSee the {licenseFile} file in the project root for full license information.", - "variables": { - "licenseName": "MIT", - "licenseFile": "LICENSE" - }, - "xmlHeader": false - }, - "layoutRules": { - "newlineAtEndOfFile": "allow", - "allowConsecutiveUsings": true - }, - "maintainabilityRules": { - "topLevelTypes": [ - "class", - "interface", - "struct", - "enum", - "delegate" - ] - }, - "orderingRules": { - "usingDirectivesPlacement": "outsideNamespace", - "systemUsingDirectivesFirst": true - } - } -} diff --git a/src/tests/.editorconfig b/src/tests/.editorconfig new file mode 100644 index 0000000..25501dd --- /dev/null +++ b/src/tests/.editorconfig @@ -0,0 +1,20 @@ +[*.cs] + +################### +# Code Analysis (CA) - Disable rules for test projects +################### +dotnet_diagnostic.CA1001.severity = none # Owns disposable fields +dotnet_diagnostic.CA1063.severity = none # Implement IDisposable correctly +dotnet_diagnostic.CA1065.severity = none # Do not raise exceptions in unexpected locations +dotnet_diagnostic.CA1812.severity = none # Avoid uninstantiated internal classes +dotnet_diagnostic.CA2213.severity = none # Disposable fields should be disposed + +################### +# PerformanceSharp / StyleSharp test relaxations imported from Primitives +################### +dotnet_diagnostic.SST1432.severity = none # Test fixtures need not be static +dotnet_diagnostic.SST2410.severity = none # A test creates the disposable it is asserting about; the test process owns it and exits +performancesharp.avoid_linq_on_hot_path = false +dotnet_diagnostic.PSH1100.severity = none # Tests can use LINQ for clarity +dotnet_diagnostic.PSH1101.severity = error # In tests, simplify LINQ Where plus terminal calls instead of banning LINQ +dotnet_diagnostic.PSH1102.severity = error # In tests, simplify LINQ type filters instead of banning LINQ diff --git a/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.General.cs b/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.General.cs index ef297dd..c575f9b 100644 --- a/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.General.cs +++ b/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.General.cs @@ -7,14 +7,10 @@ namespace ReactiveUI.Binding.Analyzer.Tests; -/// -/// Tests for — general and cross-cutting cases. -/// +/// Tests for — general and cross-cutting cases. public partial class BindingInvocationAnalyzerTests { - /// - /// Placeholder test to verify the analyzer test infrastructure works. - /// + /// Placeholder test to verify the analyzer test infrastructure works. /// A task representing the asynchronous test operation. [Test] public async Task EmptySource_NoDiagnostics() @@ -30,9 +26,7 @@ public class EmptyClass { } await Assert.That(diagnostics.Length).IsEqualTo(0); } - /// - /// Verifies that non-binding methods do not trigger any diagnostics. - /// + /// Verifies that non-binding methods do not trigger any diagnostics. /// A task representing the asynchronous test operation. [Test] public async Task NonBindingMethod_NoDiagnostics() @@ -94,11 +88,11 @@ public void Test() var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); // RXUIBIND001 for non-inline lambda - var nonInlineDiags = diagnostics.Where(d => d.Id == "RXUIBIND001").ToArray(); + var nonInlineDiags = diagnostics.Where(static d => d.Id == NonInlineLambdaDiagnosticId).ToArray(); await Assert.That(nonInlineDiags.Length).IsEqualTo(1); // RXUIBIND003 should NOT be reported because the lambda is not inline - var privateDiags = diagnostics.Where(d => d.Id == "RXUIBIND003").ToArray(); + var privateDiags = diagnostics.Where(static d => d.Id == "RXUIBIND003").ToArray(); await Assert.That(privateDiags.Length).IsEqualTo(0); } @@ -165,14 +159,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var nonInlineDiags = diagnostics.Where(d => d.Id == "RXUIBIND001").ToArray(); + var nonInlineDiags = diagnostics.Where(static d => d.Id == NonInlineLambdaDiagnosticId).ToArray(); await Assert.That(nonInlineDiags.Length).IsEqualTo(0); } - /// - /// Verifies that a block-body parenthesized lambda is still considered inline - /// and does NOT trigger RXUIBIND001. - /// + /// Verifies that a block-body parenthesized lambda is still considered inline and does NOT trigger RXUIBIND001. /// A task representing the asynchronous test operation. [Test] public async Task ParenthesizedBlockBodyLambda_IsInlineLambda_NoDiagnosticForRXUIBIND001() @@ -199,7 +190,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var nonInlineDiags = diagnostics.Where(d => d.Id == "RXUIBIND001").ToArray(); + var nonInlineDiags = diagnostics.Where(static d => d.Id == NonInlineLambdaDiagnosticId).ToArray(); await Assert.That(nonInlineDiags.Length).IsEqualTo(0); } @@ -347,9 +338,7 @@ public void Test() await Assert.That(diagnostics.Length).IsEqualTo(0); } - /// - /// Verifies BindTo with an inline target lambda accessing a public property reports no diagnostics. - /// + /// Verifies BindTo with an inline target lambda accessing a public property reports no diagnostics. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND_BindTo_InlineLambda_NoDiagnostic() @@ -377,7 +366,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var bindDiags = diagnostics.Where(d => d.Id.StartsWith("RXUIBIND", StringComparison.Ordinal)).ToArray(); + var bindDiags = diagnostics.Where(static d => d.Id.StartsWith("RXUIBIND", StringComparison.Ordinal)).ToArray(); await Assert.That(bindDiags.Length).IsEqualTo(0); } } diff --git a/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.RXUIBIND001.cs b/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.RXUIBIND001.cs index ce7cc19..1a36637 100644 --- a/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.RXUIBIND001.cs +++ b/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.RXUIBIND001.cs @@ -7,14 +7,16 @@ namespace ReactiveUI.Binding.Analyzer.Tests; -/// -/// Tests for — RXUIBIND001 (expression must be an inline lambda). -/// +/// Tests for — RXUIBIND001 (expression must be an inline lambda). public partial class BindingInvocationAnalyzerTests { - /// - /// Verifies RXUIBIND001 is reported when a non-inline lambda (variable reference) is passed. - /// + /// The diagnostic id reported for a non-inline lambda. + private const string NonInlineLambdaDiagnosticId = "RXUIBIND001"; + + /// Diagnostic count for a call whose source and target selectors are both non-inline. + private const int BothSelectorsNonInlineCount = 2; + + /// Verifies RXUIBIND001 is reported when a non-inline lambda (variable reference) is passed. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND001_NonInlineLambda_Variable_ReportsDiagnostic() @@ -43,12 +45,10 @@ public void Test() var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); await Assert.That(diagnostics.Length).IsEqualTo(1); - await Assert.That(diagnostics[0].Id).IsEqualTo("RXUIBIND001"); + await Assert.That(diagnostics[0].Id).IsEqualTo(NonInlineLambdaDiagnosticId); } - /// - /// Verifies RXUIBIND001 is NOT reported when an inline lambda is passed. - /// + /// Verifies RXUIBIND001 is NOT reported when an inline lambda is passed. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND001_InlineLambda_NoDiagnostic() @@ -78,9 +78,7 @@ public void Test() await Assert.That(diagnostics.Length).IsEqualTo(0); } - /// - /// Verifies RXUIBIND001 is reported for WhenChanging with non-inline lambda. - /// + /// Verifies RXUIBIND001 is reported for WhenChanging with non-inline lambda. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND001_WhenChanging_NonInlineLambda_ReportsDiagnostic() @@ -110,13 +108,11 @@ public void Test() var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); // Filter to only RXUIBIND001 (WhenChanging on INPC-only also fires RXUIBIND004) - var nonInlineDiags = diagnostics.Where(d => d.Id == "RXUIBIND001").ToArray(); + var nonInlineDiags = diagnostics.Where(static d => d.Id == NonInlineLambdaDiagnosticId).ToArray(); await Assert.That(nonInlineDiags.Length).IsEqualTo(1); } - /// - /// Verifies RXUIBIND001 is reported for BindOneWay with non-inline source lambda. - /// + /// Verifies RXUIBIND001 is reported for BindOneWay with non-inline source lambda. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND001_BindOneWay_NonInlineLambda_ReportsDiagnostic() @@ -151,13 +147,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var nonInlineDiags = diagnostics.Where(d => d.Id == "RXUIBIND001").ToArray(); + var nonInlineDiags = diagnostics.Where(static d => d.Id == NonInlineLambdaDiagnosticId).ToArray(); await Assert.That(nonInlineDiags.Length).IsEqualTo(1); } - /// - /// Verifies RXUIBIND001 is reported for BindTwoWay with non-inline target lambda. - /// + /// Verifies RXUIBIND001 is reported for BindTwoWay with non-inline target lambda. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND001_BindTwoWay_NonInlineLambda_ReportsDiagnostic() @@ -192,7 +186,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var nonInlineDiags = diagnostics.Where(d => d.Id == "RXUIBIND001").ToArray(); + var nonInlineDiags = diagnostics.Where(static d => d.Id == NonInlineLambdaDiagnosticId).ToArray(); await Assert.That(nonInlineDiags.Length).IsEqualTo(1); } @@ -236,15 +230,13 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var nonInlineDiags = diagnostics.Where(d => d.Id == "RXUIBIND001").ToArray(); + var nonInlineDiags = diagnostics.Where(static d => d.Id == NonInlineLambdaDiagnosticId).ToArray(); // Both source and target Expression> args are non-inline - await Assert.That(nonInlineDiags.Length).IsEqualTo(2); + await Assert.That(nonInlineDiags.Length).IsEqualTo(BothSelectorsNonInlineCount); } - /// - /// Verifies RXUIBIND001 is reported for non-inline lambda in BindInteraction. - /// + /// Verifies RXUIBIND001 is reported for non-inline lambda in BindInteraction. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND001_BindInteraction_NonInlineLambda_ReportsDiagnostic() @@ -282,13 +274,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var nonInlineDiags = diagnostics.Where(d => d.Id == "RXUIBIND001").ToArray(); + var nonInlineDiags = diagnostics.Where(static d => d.Id == NonInlineLambdaDiagnosticId).ToArray(); await Assert.That(nonInlineDiags.Length).IsEqualTo(1); } - /// - /// Verifies RXUIBIND001 is reported for BindTo with a non-inline target lambda. - /// + /// Verifies RXUIBIND001 is reported for BindTo with a non-inline target lambda. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND001_BindTo_NonInlineLambda_ReportsDiagnostic() @@ -317,7 +307,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var nonInlineDiags = diagnostics.Where(d => d.Id == "RXUIBIND001").ToArray(); + var nonInlineDiags = diagnostics.Where(static d => d.Id == NonInlineLambdaDiagnosticId).ToArray(); await Assert.That(nonInlineDiags.Length).IsEqualTo(1); } } diff --git a/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.RXUIBIND003.cs b/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.RXUIBIND003.cs index 505cb44..8c0dfa0 100644 --- a/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.RXUIBIND003.cs +++ b/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.RXUIBIND003.cs @@ -7,14 +7,13 @@ namespace ReactiveUI.Binding.Analyzer.Tests; -/// -/// Tests for — RXUIBIND003 (private or protected member access). -/// +/// Tests for — RXUIBIND003 (private or protected member access). public partial class BindingInvocationAnalyzerTests { - /// - /// Verifies RXUIBIND003 is reported when accessing a private property in a lambda. - /// + /// The diagnostic id reported for a private or protected member access. + private const string PrivateMemberDiagnosticId = "RXUIBIND003"; + + /// Verifies RXUIBIND003 is reported when accessing a private property in a lambda. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND003_PrivateProperty_ReportsDiagnostic() @@ -37,13 +36,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var privateDiags = diagnostics.Where(d => d.Id == "RXUIBIND003").ToArray(); + var privateDiags = diagnostics.Where(static d => d.Id == PrivateMemberDiagnosticId).ToArray(); await Assert.That(privateDiags.Length).IsEqualTo(1); } - /// - /// Verifies RXUIBIND003 is reported when accessing a protected property in a lambda. - /// + /// Verifies RXUIBIND003 is reported when accessing a protected property in a lambda. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND003_ProtectedProperty_ReportsDiagnostic() @@ -69,13 +66,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var privateDiags = diagnostics.Where(d => d.Id == "RXUIBIND003").ToArray(); + var privateDiags = diagnostics.Where(static d => d.Id == PrivateMemberDiagnosticId).ToArray(); await Assert.That(privateDiags.Length).IsEqualTo(1); } - /// - /// Verifies RXUIBIND003 is NOT reported for public property access. - /// + /// Verifies RXUIBIND003 is NOT reported for public property access. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND003_PublicProperty_NoDiagnostic() @@ -102,7 +97,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var privateMemberDiags = diagnostics.Where(d => d.Id == "RXUIBIND003").ToArray(); + var privateMemberDiags = diagnostics.Where(static d => d.Id == PrivateMemberDiagnosticId).ToArray(); await Assert.That(privateMemberDiags.Length).IsEqualTo(0); } @@ -132,13 +127,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var privateDiags = diagnostics.Where(d => d.Id == "RXUIBIND003").ToArray(); + var privateDiags = diagnostics.Where(static d => d.Id == PrivateMemberDiagnosticId).ToArray(); await Assert.That(privateDiags.Length).IsEqualTo(0); } - /// - /// Verifies RXUIBIND003 is reported when accessing a private property in a WhenChanging lambda. - /// + /// Verifies RXUIBIND003 is reported when accessing a private property in a WhenChanging lambda. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND003_WhenChanging_PrivateProperty_ReportsDiagnostic() @@ -162,13 +155,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var privateDiags = diagnostics.Where(d => d.Id == "RXUIBIND003").ToArray(); + var privateDiags = diagnostics.Where(static d => d.Id == PrivateMemberDiagnosticId).ToArray(); await Assert.That(privateDiags.Length).IsEqualTo(1); } - /// - /// Verifies RXUIBIND003 is reported when accessing a private property in a BindOneWay source lambda. - /// + /// Verifies RXUIBIND003 is reported when accessing a private property in a BindOneWay source lambda. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND003_BindOneWay_PrivateProperty_ReportsDiagnostic() @@ -199,13 +190,11 @@ public class MyView : INotifyPropertyChanged """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var privateDiags = diagnostics.Where(d => d.Id == "RXUIBIND003").ToArray(); + var privateDiags = diagnostics.Where(static d => d.Id == PrivateMemberDiagnosticId).ToArray(); await Assert.That(privateDiags.Length).IsEqualTo(1); } - /// - /// Verifies RXUIBIND003 with block-body lambda does not fire for BindTwoWay. - /// + /// Verifies RXUIBIND003 with block-body lambda does not fire for BindTwoWay. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND003_BindTwoWay_BlockBodyLambda_NoDiagnostic() @@ -236,14 +225,11 @@ public class MyView : INotifyPropertyChanged """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var privateDiags = diagnostics.Where(d => d.Id == "RXUIBIND003").ToArray(); + var privateDiags = diagnostics.Where(static d => d.Id == PrivateMemberDiagnosticId).ToArray(); await Assert.That(privateDiags.Length).IsEqualTo(0); } - /// - /// Verifies that a parenthesized lambda with block body does not report RXUIBIND003 - /// for private members. - /// + /// Verifies that a parenthesized lambda with block body does not report RXUIBIND003 for private members. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND003_ParenthesizedBlockBodyLambda_NoDiagnostic() @@ -266,7 +252,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var privateDiags = diagnostics.Where(d => d.Id == "RXUIBIND003").ToArray(); + var privateDiags = diagnostics.Where(static d => d.Id == PrivateMemberDiagnosticId).ToArray(); await Assert.That(privateDiags.Length).IsEqualTo(0); } @@ -301,7 +287,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var privateDiags = diagnostics.Where(d => d.Id == "RXUIBIND003").ToArray(); + var privateDiags = diagnostics.Where(static d => d.Id == PrivateMemberDiagnosticId).ToArray(); // Internal is not Private or Protected, so no diagnostic await Assert.That(privateDiags.Length).IsEqualTo(0); @@ -344,7 +330,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var privateDiags = diagnostics.Where(d => d.Id == "RXUIBIND003").ToArray(); + var privateDiags = diagnostics.Where(static d => d.Id == PrivateMemberDiagnosticId).ToArray(); await Assert.That(privateDiags.Length).IsEqualTo(0); } @@ -381,7 +367,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var privateDiags = diagnostics.Where(d => d.Id == "RXUIBIND003").ToArray(); + var privateDiags = diagnostics.Where(static d => d.Id == PrivateMemberDiagnosticId).ToArray(); await Assert.That(privateDiags.Length).IsEqualTo(1); } @@ -412,7 +398,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var privateDiags = diagnostics.Where(d => d.Id == "RXUIBIND003").ToArray(); + var privateDiags = diagnostics.Where(static d => d.Id == PrivateMemberDiagnosticId).ToArray(); await Assert.That(privateDiags.Length).IsEqualTo(1); } @@ -446,17 +432,15 @@ public void Test() var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); // RXUIBIND003 for private member access - var privateDiags = diagnostics.Where(d => d.Id == "RXUIBIND003").ToArray(); + var privateDiags = diagnostics.Where(static d => d.Id == PrivateMemberDiagnosticId).ToArray(); await Assert.That(privateDiags.Length).IsEqualTo(1); // RXUIBIND006 for field access (separate check) - var unsupportedDiags = diagnostics.Where(d => d.Id == "RXUIBIND006").ToArray(); + var unsupportedDiags = diagnostics.Where(static d => d.Id == "RXUIBIND006").ToArray(); await Assert.That(unsupportedDiags.Length).IsEqualTo(1); } - /// - /// Verifies RXUIBIND003 is reported for BindTo when the target lambda accesses a private member. - /// + /// Verifies RXUIBIND003 is reported for BindTo when the target lambda accesses a private member. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND003_BindTo_PrivateMember_ReportsDiagnostic() @@ -480,7 +464,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var privateDiags = diagnostics.Where(d => d.Id == "RXUIBIND003").ToArray(); + var privateDiags = diagnostics.Where(static d => d.Id == PrivateMemberDiagnosticId).ToArray(); await Assert.That(privateDiags.Length).IsEqualTo(1); } } diff --git a/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.RXUIBIND004.cs b/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.RXUIBIND004.cs index 6f9d835..5f839b8 100644 --- a/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.RXUIBIND004.cs +++ b/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.RXUIBIND004.cs @@ -7,11 +7,12 @@ namespace ReactiveUI.Binding.Analyzer.Tests; -/// -/// Tests for — RXUIBIND004 (before-change notification support). -/// +/// Tests for — RXUIBIND004 (before-change notification support). public partial class BindingInvocationAnalyzerTests { + /// The diagnostic id reported when a type has no before-change notification support. + private const string NoBeforeChangeSupportDiagnosticId = "RXUIBIND004"; + /// /// Verifies RXUIBIND004 is reported when WhenChanging is called on a type /// that only implements INotifyPropertyChanged (no INotifyPropertyChanging). @@ -42,14 +43,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var beforeChangeDiags = diagnostics.Where(d => d.Id == "RXUIBIND004").ToArray(); + var beforeChangeDiags = diagnostics.Where(static d => d.Id == NoBeforeChangeSupportDiagnosticId).ToArray(); await Assert.That(beforeChangeDiags.Length).IsEqualTo(1); } - /// - /// Verifies RXUIBIND004 is NOT reported when WhenChanging is called on a type - /// that implements INotifyPropertyChanging. - /// + /// Verifies RXUIBIND004 is NOT reported when WhenChanging is called on a type that implements INotifyPropertyChanging. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND004_INPChanging_NoDiagnostic() @@ -77,13 +75,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var beforeChangeDiags = diagnostics.Where(d => d.Id == "RXUIBIND004").ToArray(); + var beforeChangeDiags = diagnostics.Where(static d => d.Id == NoBeforeChangeSupportDiagnosticId).ToArray(); await Assert.That(beforeChangeDiags.Length).IsEqualTo(0); } - /// - /// Verifies RXUIBIND004 is NOT reported for WhenChanged (only applies to WhenChanging). - /// + /// Verifies RXUIBIND004 is NOT reported for WhenChanged (only applies to WhenChanging). /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND004_WhenChanged_NoDiagnostic() @@ -110,7 +106,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var beforeChangeDiags = diagnostics.Where(d => d.Id == "RXUIBIND004").ToArray(); + var beforeChangeDiags = diagnostics.Where(static d => d.Id == NoBeforeChangeSupportDiagnosticId).ToArray(); await Assert.That(beforeChangeDiags.Length).IsEqualTo(0); } @@ -143,7 +139,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var beforeChangeDiags = diagnostics.Where(d => d.Id == "RXUIBIND004").ToArray(); + var beforeChangeDiags = diagnostics.Where(static d => d.Id == NoBeforeChangeSupportDiagnosticId).ToArray(); await Assert.That(beforeChangeDiags.Length).IsEqualTo(0); } @@ -181,7 +177,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var beforeChangeDiags = diagnostics.Where(d => d.Id == "RXUIBIND004").ToArray(); + var beforeChangeDiags = diagnostics.Where(static d => d.Id == NoBeforeChangeSupportDiagnosticId).ToArray(); await Assert.That(beforeChangeDiags.Length).IsEqualTo(1); } @@ -219,7 +215,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var beforeChangeDiags = diagnostics.Where(d => d.Id == "RXUIBIND004").ToArray(); + var beforeChangeDiags = diagnostics.Where(static d => d.Id == NoBeforeChangeSupportDiagnosticId).ToArray(); await Assert.That(beforeChangeDiags.Length).IsEqualTo(1); } @@ -257,7 +253,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var beforeChangeDiags = diagnostics.Where(d => d.Id == "RXUIBIND004").ToArray(); + var beforeChangeDiags = diagnostics.Where(static d => d.Id == NoBeforeChangeSupportDiagnosticId).ToArray(); await Assert.That(beforeChangeDiags.Length).IsEqualTo(1); } @@ -295,7 +291,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var beforeChangeDiags = diagnostics.Where(d => d.Id == "RXUIBIND004").ToArray(); + var beforeChangeDiags = diagnostics.Where(static d => d.Id == NoBeforeChangeSupportDiagnosticId).ToArray(); await Assert.That(beforeChangeDiags.Length).IsEqualTo(1); } @@ -333,7 +329,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var beforeChangeDiags = diagnostics.Where(d => d.Id == "RXUIBIND004").ToArray(); + var beforeChangeDiags = diagnostics.Where(static d => d.Id == NoBeforeChangeSupportDiagnosticId).ToArray(); await Assert.That(beforeChangeDiags.Length).IsEqualTo(0); } @@ -366,7 +362,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var beforeChangeDiags = diagnostics.Where(d => d.Id == "RXUIBIND004").ToArray(); + var beforeChangeDiags = diagnostics.Where(static d => d.Id == NoBeforeChangeSupportDiagnosticId).ToArray(); await Assert.That(beforeChangeDiags.Length).IsEqualTo(1); } @@ -410,7 +406,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var beforeChangeDiags = diagnostics.Where(d => d.Id == "RXUIBIND004").ToArray(); + var beforeChangeDiags = diagnostics.Where(static d => d.Id == NoBeforeChangeSupportDiagnosticId).ToArray(); await Assert.That(beforeChangeDiags.Length).IsEqualTo(1); } @@ -445,7 +441,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var beforeChangeDiags = diagnostics.Where(d => d.Id == "RXUIBIND004").ToArray(); + var beforeChangeDiags = diagnostics.Where(static d => d.Id == NoBeforeChangeSupportDiagnosticId).ToArray(); await Assert.That(beforeChangeDiags.Length).IsEqualTo(1); var message = beforeChangeDiags[0].GetMessage(); await Assert.That(message).Contains("INotifyPropertyChanged"); @@ -485,7 +481,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var beforeChangeDiags = diagnostics.Where(d => d.Id == "RXUIBIND004").ToArray(); + var beforeChangeDiags = diagnostics.Where(static d => d.Id == NoBeforeChangeSupportDiagnosticId).ToArray(); await Assert.That(beforeChangeDiags.Length).IsEqualTo(1); var message = beforeChangeDiags[0].GetMessage(); await Assert.That(message).Contains("WPF DependencyObject"); @@ -525,7 +521,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var beforeChangeDiags = diagnostics.Where(d => d.Id == "RXUIBIND004").ToArray(); + var beforeChangeDiags = diagnostics.Where(static d => d.Id == NoBeforeChangeSupportDiagnosticId).ToArray(); await Assert.That(beforeChangeDiags.Length).IsEqualTo(1); var message = beforeChangeDiags[0].GetMessage(); await Assert.That(message).Contains("WinUI DependencyObject"); @@ -565,7 +561,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var beforeChangeDiags = diagnostics.Where(d => d.Id == "RXUIBIND004").ToArray(); + var beforeChangeDiags = diagnostics.Where(static d => d.Id == NoBeforeChangeSupportDiagnosticId).ToArray(); await Assert.That(beforeChangeDiags.Length).IsEqualTo(1); var message = beforeChangeDiags[0].GetMessage(); await Assert.That(message).Contains("WinForms Component"); @@ -605,7 +601,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var beforeChangeDiags = diagnostics.Where(d => d.Id == "RXUIBIND004").ToArray(); + var beforeChangeDiags = diagnostics.Where(static d => d.Id == NoBeforeChangeSupportDiagnosticId).ToArray(); await Assert.That(beforeChangeDiags.Length).IsEqualTo(1); var message = beforeChangeDiags[0].GetMessage(); await Assert.That(message).Contains("Android View"); @@ -641,7 +637,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var beforeChangeDiags = diagnostics.Where(d => d.Id == "RXUIBIND004").ToArray(); + var beforeChangeDiags = diagnostics.Where(static d => d.Id == NoBeforeChangeSupportDiagnosticId).ToArray(); await Assert.That(beforeChangeDiags.Length).IsEqualTo(1); var message = beforeChangeDiags[0].GetMessage(); await Assert.That(message).Contains("unknown"); @@ -684,7 +680,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var beforeChangeDiags = diagnostics.Where(d => d.Id == "RXUIBIND004").ToArray(); + var beforeChangeDiags = diagnostics.Where(static d => d.Id == NoBeforeChangeSupportDiagnosticId).ToArray(); await Assert.That(beforeChangeDiags.Length).IsEqualTo(0); } @@ -735,7 +731,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var beforeChangeDiags = diagnostics.Where(d => d.Id == "RXUIBIND004").ToArray(); + var beforeChangeDiags = diagnostics.Where(static d => d.Id == NoBeforeChangeSupportDiagnosticId).ToArray(); await Assert.That(beforeChangeDiags.Length).IsEqualTo(0); } } diff --git a/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.RXUIBIND005.cs b/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.RXUIBIND005.cs index 90c1d17..3ae3c7d 100644 --- a/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.RXUIBIND005.cs +++ b/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.RXUIBIND005.cs @@ -7,14 +7,13 @@ namespace ReactiveUI.Binding.Analyzer.Tests; -/// -/// Tests for — RXUIBIND005 (INotifyDataErrorInfo validation). -/// +/// Tests for — RXUIBIND005 (INotifyDataErrorInfo validation). public partial class BindingInvocationAnalyzerTests { - /// - /// Verifies RXUIBIND005 is reported when BindOneWay source type implements INotifyDataErrorInfo. - /// + /// The diagnostic id reported when validation binding requires the runtime engine. + private const string ValidationNotGeneratedDiagnosticId = "RXUIBIND005"; + + /// Verifies RXUIBIND005 is reported when BindOneWay source type implements INotifyDataErrorInfo. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND005_BindOneWay_WithDataErrorInfo_ReportsDiagnostic() @@ -51,13 +50,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var validationDiags = diagnostics.Where(d => d.Id == "RXUIBIND005").ToArray(); + var validationDiags = diagnostics.Where(static d => d.Id == ValidationNotGeneratedDiagnosticId).ToArray(); await Assert.That(validationDiags.Length).IsEqualTo(1); } - /// - /// Verifies RXUIBIND005 is reported for BindTwoWay when source implements INotifyDataErrorInfo. - /// + /// Verifies RXUIBIND005 is reported for BindTwoWay when source implements INotifyDataErrorInfo. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND005_BindTwoWay_WithDataErrorInfo_ReportsDiagnostic() @@ -94,13 +91,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var validationDiags = diagnostics.Where(d => d.Id == "RXUIBIND005").ToArray(); + var validationDiags = diagnostics.Where(static d => d.Id == ValidationNotGeneratedDiagnosticId).ToArray(); await Assert.That(validationDiags.Length).IsEqualTo(1); } - /// - /// Verifies RXUIBIND005 is NOT reported when source type does not implement INotifyDataErrorInfo. - /// + /// Verifies RXUIBIND005 is NOT reported when source type does not implement INotifyDataErrorInfo. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND005_NoDataErrorInfo_NoDiagnostic() @@ -134,13 +129,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var validationDiags = diagnostics.Where(d => d.Id == "RXUIBIND005").ToArray(); + var validationDiags = diagnostics.Where(static d => d.Id == ValidationNotGeneratedDiagnosticId).ToArray(); await Assert.That(validationDiags.Length).IsEqualTo(0); } - /// - /// Verifies RXUIBIND005 is NOT reported for WhenChanged (only applies to binding methods). - /// + /// Verifies RXUIBIND005 is NOT reported for WhenChanged (only applies to binding methods). /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND005_WhenChanged_NoDiagnostic() @@ -170,13 +163,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var validationDiags = diagnostics.Where(d => d.Id == "RXUIBIND005").ToArray(); + var validationDiags = diagnostics.Where(static d => d.Id == ValidationNotGeneratedDiagnosticId).ToArray(); await Assert.That(validationDiags.Length).IsEqualTo(0); } - /// - /// Verifies that RXUIBIND005 is NOT reported for WhenChanging (only applies to BindOneWay/BindTwoWay). - /// + /// Verifies that RXUIBIND005 is NOT reported for WhenChanging (only applies to BindOneWay/BindTwoWay). /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND005_WhenChanging_NoDiagnostic() @@ -207,7 +198,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var validationDiags = diagnostics.Where(d => d.Id == "RXUIBIND005").ToArray(); + var validationDiags = diagnostics.Where(static d => d.Id == ValidationNotGeneratedDiagnosticId).ToArray(); await Assert.That(validationDiags.Length).IsEqualTo(0); } @@ -256,7 +247,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var validationDiags = diagnostics.Where(d => d.Id == "RXUIBIND005").ToArray(); + var validationDiags = diagnostics.Where(static d => d.Id == ValidationNotGeneratedDiagnosticId).ToArray(); await Assert.That(validationDiags.Length).IsEqualTo(1); } @@ -298,7 +289,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var validationDiags = diagnostics.Where(d => d.Id == "RXUIBIND005").ToArray(); + var validationDiags = diagnostics.Where(static d => d.Id == ValidationNotGeneratedDiagnosticId).ToArray(); await Assert.That(validationDiags.Length).IsEqualTo(0); } @@ -342,7 +333,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var validationDiags = diagnostics.Where(d => d.Id == "RXUIBIND005").ToArray(); + var validationDiags = diagnostics.Where(static d => d.Id == ValidationNotGeneratedDiagnosticId).ToArray(); await Assert.That(validationDiags.Length).IsEqualTo(1); var message = validationDiags[0].GetMessage(); await Assert.That(message).Contains("ValidatingViewModel"); @@ -402,7 +393,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var validationDiags = diagnostics.Where(d => d.Id == "RXUIBIND005").ToArray(); + var validationDiags = diagnostics.Where(static d => d.Id == ValidationNotGeneratedDiagnosticId).ToArray(); await Assert.That(validationDiags.Length).IsEqualTo(0); } } diff --git a/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.RXUIBIND006.cs b/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.RXUIBIND006.cs index e44da55..0e6a0a5 100644 --- a/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.RXUIBIND006.cs +++ b/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.RXUIBIND006.cs @@ -7,14 +7,13 @@ namespace ReactiveUI.Binding.Analyzer.Tests; -/// -/// Tests for — RXUIBIND006 (unsupported path segment). -/// +/// Tests for — RXUIBIND006 (unsupported path segment). public partial class BindingInvocationAnalyzerTests { - /// - /// Verifies RXUIBIND006 is reported when a property path contains an indexer. - /// + /// The diagnostic id reported for an unsupported property-path segment. + private const string UnsupportedPathSegmentDiagnosticId = "RXUIBIND006"; + + /// Verifies RXUIBIND006 is reported when a property path contains an indexer. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND006_Indexer_InPropertyPath_ReportsDiagnostic() @@ -41,13 +40,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var unsupportedDiags = diagnostics.Where(d => d.Id == "RXUIBIND006").ToArray(); + var unsupportedDiags = diagnostics.Where(static d => d.Id == UnsupportedPathSegmentDiagnosticId).ToArray(); await Assert.That(unsupportedDiags.Length).IsEqualTo(1); } - /// - /// Verifies RXUIBIND006 is reported when a property path contains a field access. - /// + /// Verifies RXUIBIND006 is reported when a property path contains a field access. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND006_FieldAccess_InPropertyPath_ReportsDiagnostic() @@ -74,13 +71,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var unsupportedDiags = diagnostics.Where(d => d.Id == "RXUIBIND006").ToArray(); + var unsupportedDiags = diagnostics.Where(static d => d.Id == UnsupportedPathSegmentDiagnosticId).ToArray(); await Assert.That(unsupportedDiags.Length).IsEqualTo(1); } - /// - /// Verifies RXUIBIND006 is reported when a property path contains a method call. - /// + /// Verifies RXUIBIND006 is reported when a property path contains a method call. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND006_MethodCall_InPropertyPath_ReportsDiagnostic() @@ -107,13 +102,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var unsupportedDiags = diagnostics.Where(d => d.Id == "RXUIBIND006").ToArray(); + var unsupportedDiags = diagnostics.Where(static d => d.Id == UnsupportedPathSegmentDiagnosticId).ToArray(); await Assert.That(unsupportedDiags.Length).IsEqualTo(1); } - /// - /// Verifies RXUIBIND006 is NOT reported for simple property chain. - /// + /// Verifies RXUIBIND006 is NOT reported for simple property chain. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND006_SimplePropertyChain_NoDiagnostic() @@ -146,7 +139,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var unsupportedDiags = diagnostics.Where(d => d.Id == "RXUIBIND006").ToArray(); + var unsupportedDiags = diagnostics.Where(static d => d.Id == UnsupportedPathSegmentDiagnosticId).ToArray(); await Assert.That(unsupportedDiags.Length).IsEqualTo(0); } @@ -177,7 +170,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var unsupportedDiags = diagnostics.Where(d => d.Id == "RXUIBIND006").ToArray(); + var unsupportedDiags = diagnostics.Where(static d => d.Id == UnsupportedPathSegmentDiagnosticId).ToArray(); await Assert.That(unsupportedDiags.Length).IsEqualTo(0); } @@ -217,7 +210,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var unsupportedDiags = diagnostics.Where(d => d.Id == "RXUIBIND006").ToArray(); + var unsupportedDiags = diagnostics.Where(static d => d.Id == UnsupportedPathSegmentDiagnosticId).ToArray(); await Assert.That(unsupportedDiags.Length).IsEqualTo(1); } @@ -257,14 +250,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var unsupportedDiags = diagnostics.Where(d => d.Id == "RXUIBIND006").ToArray(); + var unsupportedDiags = diagnostics.Where(static d => d.Id == UnsupportedPathSegmentDiagnosticId).ToArray(); await Assert.That(unsupportedDiags.Length).IsEqualTo(1); } - /// - /// Verifies RXUIBIND006 is reported for BindOneWay when source property path - /// contains a method call. - /// + /// Verifies RXUIBIND006 is reported for BindOneWay when source property path contains a method call. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND006_BindOneWay_MethodCallInPath_ReportsDiagnostic() @@ -298,14 +288,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var unsupportedDiags = diagnostics.Where(d => d.Id == "RXUIBIND006").ToArray(); + var unsupportedDiags = diagnostics.Where(static d => d.Id == UnsupportedPathSegmentDiagnosticId).ToArray(); await Assert.That(unsupportedDiags.Length).IsEqualTo(1); } - /// - /// Verifies RXUIBIND006 is reported for BindTwoWay when target property path - /// contains a field access. - /// + /// Verifies RXUIBIND006 is reported for BindTwoWay when target property path contains a field access. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND006_BindTwoWay_FieldInTargetPath_ReportsDiagnostic() @@ -339,13 +326,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var unsupportedDiags = diagnostics.Where(d => d.Id == "RXUIBIND006").ToArray(); + var unsupportedDiags = diagnostics.Where(static d => d.Id == UnsupportedPathSegmentDiagnosticId).ToArray(); await Assert.That(unsupportedDiags.Length).IsEqualTo(1); } - /// - /// Verifies RXUIBIND006 is reported for a field access in the middle of a property chain. - /// + /// Verifies RXUIBIND006 is reported for a field access in the middle of a property chain. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND006_FieldInChain_ReportsDiagnostic() @@ -378,13 +363,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var unsupportedDiags = diagnostics.Where(d => d.Id == "RXUIBIND006").ToArray(); + var unsupportedDiags = diagnostics.Where(static d => d.Id == UnsupportedPathSegmentDiagnosticId).ToArray(); await Assert.That(unsupportedDiags.Length).IsEqualTo(1); } - /// - /// Verifies RXUIBIND006 is reported for WhenChanging with a method call in the property path. - /// + /// Verifies RXUIBIND006 is reported for WhenChanging with a method call in the property path. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND006_WhenChanging_MethodCallInPath_ReportsDiagnostic() @@ -412,13 +395,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var unsupportedDiags = diagnostics.Where(d => d.Id == "RXUIBIND006").ToArray(); + var unsupportedDiags = diagnostics.Where(static d => d.Id == UnsupportedPathSegmentDiagnosticId).ToArray(); await Assert.That(unsupportedDiags.Length).IsEqualTo(1); } - /// - /// Verifies RXUIBIND006 is reported for WhenChanging with a field access in the property path. - /// + /// Verifies RXUIBIND006 is reported for WhenChanging with a field access in the property path. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND006_WhenChanging_FieldAccess_ReportsDiagnostic() @@ -446,13 +427,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var unsupportedDiags = diagnostics.Where(d => d.Id == "RXUIBIND006").ToArray(); + var unsupportedDiags = diagnostics.Where(static d => d.Id == UnsupportedPathSegmentDiagnosticId).ToArray(); await Assert.That(unsupportedDiags.Length).IsEqualTo(1); } - /// - /// Verifies RXUIBIND006 is reported for an indexer access in a BindOneWay source lambda. - /// + /// Verifies RXUIBIND006 is reported for an indexer access in a BindOneWay source lambda. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND006_BindOneWay_IndexerInPath_ReportsDiagnostic() @@ -486,14 +465,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var unsupportedDiags = diagnostics.Where(d => d.Id == "RXUIBIND006").ToArray(); + var unsupportedDiags = diagnostics.Where(static d => d.Id == UnsupportedPathSegmentDiagnosticId).ToArray(); await Assert.That(unsupportedDiags.Length).IsEqualTo(1); } - /// - /// Verifies that a parenthesized lambda with block body does not report RXUIBIND006 - /// for unsupported path segments. - /// + /// Verifies that a parenthesized lambda with block body does not report RXUIBIND006 for unsupported path segments. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND006_ParenthesizedBlockBodyLambda_NoDiagnostic() @@ -517,7 +493,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var unsupportedDiags = diagnostics.Where(d => d.Id == "RXUIBIND006").ToArray(); + var unsupportedDiags = diagnostics.Where(static d => d.Id == UnsupportedPathSegmentDiagnosticId).ToArray(); await Assert.That(unsupportedDiags.Length).IsEqualTo(0); } @@ -552,7 +528,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var unsupportedDiags = diagnostics.Where(d => d.Id == "RXUIBIND006").ToArray(); + var unsupportedDiags = diagnostics.Where(static d => d.Id == UnsupportedPathSegmentDiagnosticId).ToArray(); // Const field is excluded from the field check — no diagnostic await Assert.That(unsupportedDiags.Length).IsEqualTo(0); @@ -587,7 +563,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var unsupportedDiags = diagnostics.Where(d => d.Id == "RXUIBIND006").ToArray(); + var unsupportedDiags = diagnostics.Where(static d => d.Id == UnsupportedPathSegmentDiagnosticId).ToArray(); await Assert.That(unsupportedDiags.Length).IsEqualTo(0); } @@ -628,7 +604,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var unsupportedDiags = diagnostics.Where(d => d.Id == "RXUIBIND006").ToArray(); + var unsupportedDiags = diagnostics.Where(static d => d.Id == UnsupportedPathSegmentDiagnosticId).ToArray(); await Assert.That(unsupportedDiags.Length).IsEqualTo(1); } @@ -662,13 +638,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var unsupportedDiags = diagnostics.Where(d => d.Id == "RXUIBIND006").ToArray(); + var unsupportedDiags = diagnostics.Where(static d => d.Id == UnsupportedPathSegmentDiagnosticId).ToArray(); await Assert.That(unsupportedDiags.Length).IsEqualTo(1); } - /// - /// Verifies RXUIBIND006 is reported for BindTo when the target property path contains a method call. - /// + /// Verifies RXUIBIND006 is reported for BindTo when the target property path contains a method call. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND006_BindTo_MethodCallInPath_ReportsDiagnostic() @@ -696,7 +670,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var unsupportedDiags = diagnostics.Where(d => d.Id == "RXUIBIND006").ToArray(); + var unsupportedDiags = diagnostics.Where(static d => d.Id == UnsupportedPathSegmentDiagnosticId).ToArray(); await Assert.That(unsupportedDiags.Length).IsEqualTo(1); } } diff --git a/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.RXUIBIND007.cs b/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.RXUIBIND007.cs index 7833755..0811419 100644 --- a/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.RXUIBIND007.cs +++ b/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.RXUIBIND007.cs @@ -7,14 +7,13 @@ namespace ReactiveUI.Binding.Analyzer.Tests; -/// -/// Tests for — RXUIBIND007 (BindCommand bindable event). -/// +/// Tests for — RXUIBIND007 (BindCommand bindable event). public partial class BindingInvocationAnalyzerTests { - /// - /// Verifies RXUIBIND007 is reported when the control has no default bindable event. - /// + /// The diagnostic id reported when a control has no default bindable event. + private const string NoBindableEventDiagnosticId = "RXUIBIND007"; + + /// Verifies RXUIBIND007 is reported when the control has no default bindable event. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND007_NoBindableEvent_ReportsDiagnostic() @@ -52,13 +51,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var eventDiags = diagnostics.Where(d => d.Id == "RXUIBIND007").ToArray(); + var eventDiags = diagnostics.Where(static d => d.Id == NoBindableEventDiagnosticId).ToArray(); await Assert.That(eventDiags.Length).IsEqualTo(1); } - /// - /// Verifies RXUIBIND007 is not reported when the control has a Click event. - /// + /// Verifies RXUIBIND007 is not reported when the control has a Click event. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND007_ControlWithClickEvent_NoDiagnostic() @@ -99,13 +96,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var eventDiags = diagnostics.Where(d => d.Id == "RXUIBIND007").ToArray(); + var eventDiags = diagnostics.Where(static d => d.Id == NoBindableEventDiagnosticId).ToArray(); await Assert.That(eventDiags.Length).IsEqualTo(0); } - /// - /// Verifies RXUIBIND007 is not reported when toEvent is explicitly specified. - /// + /// Verifies RXUIBIND007 is not reported when toEvent is explicitly specified. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND007_WithExplicitToEvent_NoDiagnostic() @@ -143,7 +138,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var eventDiags = diagnostics.Where(d => d.Id == "RXUIBIND007").ToArray(); + var eventDiags = diagnostics.Where(static d => d.Id == NoBindableEventDiagnosticId).ToArray(); await Assert.That(eventDiags.Length).IsEqualTo(0); } @@ -191,13 +186,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var eventDiags = diagnostics.Where(d => d.Id == "RXUIBIND007").ToArray(); + var eventDiags = diagnostics.Where(static d => d.Id == NoBindableEventDiagnosticId).ToArray(); await Assert.That(eventDiags.Length).IsEqualTo(1); } - /// - /// Verifies RXUIBIND007 is not reported when the control has a TouchUpInside event. - /// + /// Verifies RXUIBIND007 is not reported when the control has a TouchUpInside event. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND007_ControlWithTouchUpInsideEvent_NoDiagnostic() @@ -238,13 +231,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var eventDiags = diagnostics.Where(d => d.Id == "RXUIBIND007").ToArray(); + var eventDiags = diagnostics.Where(static d => d.Id == NoBindableEventDiagnosticId).ToArray(); await Assert.That(eventDiags.Length).IsEqualTo(0); } - /// - /// Verifies RXUIBIND007 is not reported when the control has a MouseUp event. - /// + /// Verifies RXUIBIND007 is not reported when the control has a MouseUp event. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND007_ControlWithMouseUpEvent_NoDiagnostic() @@ -285,13 +276,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var eventDiags = diagnostics.Where(d => d.Id == "RXUIBIND007").ToArray(); + var eventDiags = diagnostics.Where(static d => d.Id == NoBindableEventDiagnosticId).ToArray(); await Assert.That(eventDiags.Length).IsEqualTo(0); } - /// - /// Verifies RXUIBIND007 is not reported when the control has a Pressed event. - /// + /// Verifies RXUIBIND007 is not reported when the control has a Pressed event. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND007_ControlWithPressedEvent_NoDiagnostic() @@ -332,7 +321,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var eventDiags = diagnostics.Where(d => d.Id == "RXUIBIND007").ToArray(); + var eventDiags = diagnostics.Where(static d => d.Id == NoBindableEventDiagnosticId).ToArray(); await Assert.That(eventDiags.Length).IsEqualTo(0); } @@ -377,7 +366,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var eventDiags = diagnostics.Where(d => d.Id == "RXUIBIND007").ToArray(); + var eventDiags = diagnostics.Where(static d => d.Id == NoBindableEventDiagnosticId).ToArray(); await Assert.That(eventDiags.Length).IsEqualTo(1); } @@ -425,7 +414,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var eventDiags = diagnostics.Where(d => d.Id == "RXUIBIND007").ToArray(); + var eventDiags = diagnostics.Where(static d => d.Id == NoBindableEventDiagnosticId).ToArray(); await Assert.That(eventDiags.Length).IsEqualTo(0); } } diff --git a/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.RXUIBIND008.cs b/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.RXUIBIND008.cs index 57c9518..0ea1e3b 100644 --- a/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.RXUIBIND008.cs +++ b/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.RXUIBIND008.cs @@ -7,11 +7,12 @@ namespace ReactiveUI.Binding.Analyzer.Tests; -/// -/// Tests for — RXUIBIND008 (interaction type). -/// +/// Tests for — RXUIBIND008 (interaction type). public partial class BindingInvocationAnalyzerTests { + /// The diagnostic id reported for an invalid interaction type. + private const string InvalidInteractionTypeDiagnosticId = "RXUIBIND008"; + /// /// Verifies RXUIBIND008 is reported when the interaction property type does not implement IInteraction. /// Uses the unconstrained BindInteraction overload so the call compiles despite the wrong property type. @@ -50,13 +51,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var interactionDiags = diagnostics.Where(d => d.Id == "RXUIBIND008").ToArray(); + var interactionDiags = diagnostics.Where(static d => d.Id == InvalidInteractionTypeDiagnosticId).ToArray(); await Assert.That(interactionDiags.Length).IsEqualTo(1); } - /// - /// Verifies RXUIBIND008 is not reported when the property is a valid IInteraction type. - /// + /// Verifies RXUIBIND008 is not reported when the property is a valid IInteraction type. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND008_ValidInteractionType_NoDiagnostic() @@ -93,7 +92,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var interactionDiags = diagnostics.Where(d => d.Id == "RXUIBIND008").ToArray(); + var interactionDiags = diagnostics.Where(static d => d.Id == InvalidInteractionTypeDiagnosticId).ToArray(); await Assert.That(interactionDiags.Length).IsEqualTo(0); } @@ -135,13 +134,11 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var interactionDiags = diagnostics.Where(d => d.Id == "RXUIBIND008").ToArray(); + var interactionDiags = diagnostics.Where(static d => d.Id == InvalidInteractionTypeDiagnosticId).ToArray(); await Assert.That(interactionDiags.Length).IsEqualTo(0); } - /// - /// Verifies RXUIBIND008 check uses parenthesized lambda for BindInteraction property path. - /// + /// Verifies RXUIBIND008 check uses parenthesized lambda for BindInteraction property path. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND008_ParenthesizedLambda_ValidInteraction_NoDiagnostic() @@ -178,7 +175,7 @@ public void Test() """; var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); - var interactionDiags = diagnostics.Where(d => d.Id == "RXUIBIND008").ToArray(); + var interactionDiags = diagnostics.Where(static d => d.Id == InvalidInteractionTypeDiagnosticId).ToArray(); await Assert.That(interactionDiags.Length).IsEqualTo(0); } } diff --git a/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.cs b/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.cs index aa110e9..62d34cc 100644 --- a/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.cs +++ b/src/tests/ReactiveUI.Binding.Analyzer.Tests/BindingInvocationAnalyzerTests.cs @@ -6,9 +6,7 @@ namespace ReactiveUI.Binding.Analyzer.Tests; -/// -/// Tests for . -/// +/// Tests for . public partial class BindingInvocationAnalyzerTests { /// @@ -65,9 +63,7 @@ public static IDisposable BindTo( } """; - /// - /// Preamble with BindInteraction and BindCommand stub methods. - /// + /// Preamble with BindInteraction and BindCommand stub methods. private const string InteractionCommandPreamble = """ using System; using System.ComponentModel; diff --git a/src/tests/ReactiveUI.Binding.Analyzer.Tests/Helpers/AnalyzerHelpersTests.cs b/src/tests/ReactiveUI.Binding.Analyzer.Tests/Helpers/AnalyzerHelpersTests.cs index 27fa2f3..fd1f0c6 100644 --- a/src/tests/ReactiveUI.Binding.Analyzer.Tests/Helpers/AnalyzerHelpersTests.cs +++ b/src/tests/ReactiveUI.Binding.Analyzer.Tests/Helpers/AnalyzerHelpersTests.cs @@ -9,14 +9,10 @@ namespace ReactiveUI.Binding.Analyzer.Tests.Helpers; -/// -/// Tests for . -/// +/// Tests for . public class AnalyzerHelpersTests { - /// - /// Verifies that ExtractFirstTypeArgument returns null when the method has no type arguments. - /// + /// Verifies that ExtractFirstTypeArgument returns null when the method has no type arguments. /// A task representing the asynchronous test operation. [Test] public async Task ExtractFirstTypeArgument_NoTypeArguments_ReturnsNull() @@ -47,9 +43,7 @@ public void NonGenericMethod() { } await Assert.That(result).IsNull(); } - /// - /// Verifies that ExtractFirstTypeArgument returns the type when the method has a named type argument. - /// + /// Verifies that ExtractFirstTypeArgument returns the type when the method has a named type argument. /// A task representing the asynchronous test operation. [Test] public async Task ExtractFirstTypeArgument_WithNamedTypeArgument_ReturnsType() @@ -86,31 +80,26 @@ public void Usage() await Assert.That(result!.Name).IsEqualTo("String"); } - /// - /// Verifies that IsBindingExtensionMethod returns false when ContainingType is null. - /// + /// Verifies that IsBindingExtensionMethod returns false when ContainingType is null. /// A task representing the asynchronous test operation. [Test] public async Task IsBindingExtensionMethod_NullContainingType_ReturnsFalse() { var methodSymbol = Substitute.For(); - methodSymbol.ContainingType.Returns((INamedTypeSymbol?)null); + _ = methodSymbol.ContainingType.Returns((INamedTypeSymbol?)null); var result = AnalyzerHelpers.IsBindingExtensionMethod(methodSymbol); await Assert.That(result).IsFalse(); } - /// - /// Verifies that ExtractFirstTypeArgument returns null when TypeArguments is empty - /// (using a substitute method symbol). - /// + /// Verifies that ExtractFirstTypeArgument returns null when TypeArguments is empty (using a substitute method symbol). /// A task representing the asynchronous test operation. [Test] public async Task ExtractFirstTypeArgument_EmptyTypeArguments_ReturnsNull_Substitute() { var methodSymbol = Substitute.For(); - methodSymbol.TypeArguments.Returns([]); + _ = methodSymbol.TypeArguments.Returns([]); var result = AnalyzerHelpers.ExtractFirstTypeArgument(methodSymbol); @@ -151,9 +140,7 @@ public void DoSomething() { } await Assert.That(result).IsFalse(); } - /// - /// Verifies that IsBindingExtensionMethod returns true for a method on the generated extension class. - /// + /// Verifies that IsBindingExtensionMethod returns true for a method on the generated extension class. /// A task representing the asynchronous test operation. [Test] public async Task IsBindingExtensionMethod_GeneratedClass_ReturnsTrue() @@ -184,9 +171,7 @@ public static void WhenChanged() { } await Assert.That(result).IsTrue(); } - /// - /// Verifies that IsBindingExtensionMethod returns true for a method on the stub extension class. - /// + /// Verifies that IsBindingExtensionMethod returns true for a method on the stub extension class. /// A task representing the asynchronous test operation. [Test] public async Task IsBindingExtensionMethod_StubClass_ReturnsTrue() @@ -217,9 +202,7 @@ public static void WhenChanged() { } await Assert.That(result).IsTrue(); } - /// - /// Verifies that IsInlineLambda returns true for a SimpleLambdaExpressionSyntax. - /// + /// Verifies that IsInlineLambda returns true for a SimpleLambdaExpressionSyntax. /// A task representing the asynchronous test operation. [Test] public async Task IsInlineLambda_SimpleLambda_ReturnsTrue() @@ -230,9 +213,7 @@ public async Task IsInlineLambda_SimpleLambda_ReturnsTrue() await Assert.That(result).IsTrue(); } - /// - /// Verifies that IsInlineLambda returns true for a ParenthesizedLambdaExpressionSyntax. - /// + /// Verifies that IsInlineLambda returns true for a ParenthesizedLambdaExpressionSyntax. /// A task representing the asynchronous test operation. [Test] public async Task IsInlineLambda_ParenthesizedLambda_ReturnsTrue() @@ -243,9 +224,7 @@ public async Task IsInlineLambda_ParenthesizedLambda_ReturnsTrue() await Assert.That(result).IsTrue(); } - /// - /// Verifies that IsInlineLambda returns false for a non-lambda expression. - /// + /// Verifies that IsInlineLambda returns false for a non-lambda expression. /// A task representing the asynchronous test operation. [Test] public async Task IsInlineLambda_Identifier_ReturnsFalse() @@ -256,9 +235,7 @@ public async Task IsInlineLambda_Identifier_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies that ImplementsInterface returns false when the type does not implement the interface. - /// + /// Verifies that ImplementsInterface returns false when the type does not implement the interface. /// A task representing the asynchronous test operation. [Test] public async Task ImplementsInterface_DoesNotImplement_ReturnsFalse() @@ -288,9 +265,7 @@ public class PlainClass { } await Assert.That(result).IsFalse(); } - /// - /// Verifies that ImplementsInterface returns true when the type implements the interface. - /// + /// Verifies that ImplementsInterface returns true when the type implements the interface. /// A task representing the asynchronous test operation. [Test] public async Task ImplementsInterface_Implements_ReturnsTrue() @@ -323,9 +298,7 @@ public class ObservableClass : INotifyPropertyChanged await Assert.That(result).IsTrue(); } - /// - /// Verifies that InheritsFrom returns false when the type does not inherit from the base type. - /// + /// Verifies that InheritsFrom returns false when the type does not inherit from the base type. /// A task representing the asynchronous test operation. [Test] public async Task InheritsFrom_DoesNotInherit_ReturnsFalse() @@ -355,9 +328,7 @@ public class UnrelatedClass { } await Assert.That(result).IsFalse(); } - /// - /// Verifies that InheritsFrom returns true when the type inherits from the base type. - /// + /// Verifies that InheritsFrom returns true when the type inherits from the base type. /// A task representing the asynchronous test operation. [Test] public async Task InheritsFrom_Inherits_ReturnsTrue() @@ -387,10 +358,7 @@ public class DerivedClass : BaseClass { } await Assert.That(result).IsTrue(); } - /// - /// Verifies that LacksObservableMechanism returns false for a non-generic method - /// (no type arguments to extract). - /// + /// Verifies that LacksObservableMechanism returns false for a non-generic method (no type arguments to extract). /// A task representing the asynchronous test operation. [Test] public async Task LacksObservableMechanism_NonGenericMethod_ReturnsFalse() @@ -403,10 +371,7 @@ public async Task LacksObservableMechanism_NonGenericMethod_ReturnsFalse() await Assert.That(sourceType).IsNull(); } - /// - /// Verifies that LacksObservableMechanism returns false for a generic method - /// whose first type argument implements INPC. - /// + /// Verifies that LacksObservableMechanism returns false for a generic method whose first type argument implements INPC. /// A task representing the asynchronous test operation. [Test] public async Task LacksObservableMechanism_GenericWithINPC_ReturnsFalse() @@ -465,10 +430,7 @@ public void M(T obj) where T : class { } await Assert.That(sourceType!.Name).IsEqualTo("PlainVm"); } - /// - /// Verifies that LacksBeforeChangeSupport returns false for a non-generic method - /// (no type arguments to extract). - /// + /// Verifies that LacksBeforeChangeSupport returns false for a non-generic method (no type arguments to extract). /// A task representing the asynchronous test operation. [Test] public async Task LacksBeforeChangeSupport_NonGenericMethod_ReturnsFalse() @@ -526,10 +488,7 @@ public void M(T obj) where T : class { } await Assert.That(mechanism).Contains("INotifyPropertyChanged"); } - /// - /// Verifies that ImplementsDataErrorInfo returns false for a non-generic method - /// (no type arguments to extract). - /// + /// Verifies that ImplementsDataErrorInfo returns false for a non-generic method (no type arguments to extract). /// A task representing the asynchronous test operation. [Test] public async Task ImplementsDataErrorInfo_NonGenericMethod_ReturnsFalse() @@ -641,9 +600,7 @@ public void M(T obj) where T : class { } await Assert.That(sourceType!.Name).IsEqualTo("MyVm"); } - /// - /// Verifies that HasObservableMechanism returns true when the type implements IReactiveObject. - /// + /// Verifies that HasObservableMechanism returns true when the type implements IReactiveObject. /// A task representing the asynchronous test operation. [Test] public async Task HasObservableMechanism_IReactiveObject_ReturnsTrue() @@ -703,7 +660,7 @@ public void M(T obj) where T : class { } var classDecl = (await tree.GetRootAsync()) .DescendantNodes() .OfType() - .First(c => c.Identifier.Text == "MyVm"); + .First(static c => c.Identifier.Text == "MyVm"); var typeSymbol = (INamedTypeSymbol)model.GetDeclaredSymbol(classDecl)!; @@ -712,9 +669,7 @@ public void M(T obj) where T : class { } await Assert.That(result).IsFalse(); } - /// - /// Gets a named type symbol from a compilation by class name. - /// + /// Gets a named type symbol from a compilation by class name. /// The compilation. /// The class name to find. /// The named type symbol. @@ -731,17 +686,13 @@ private static INamedTypeSymbol GetNamedTypeSymbol(CSharpCompilation compilation return (INamedTypeSymbol)model.GetDeclaredSymbol(classDecl)!; } - /// - /// Creates a compilation from the specified source code. - /// + /// Creates a compilation from the specified source code. /// The source code. /// A CSharpCompilation. private static CSharpCompilation CreateCompilation(string source) => AnalyzerTestHelper.CreateCompilation(source); - /// - /// Gets a non-generic method symbol and its compilation. - /// + /// Gets a non-generic method symbol and its compilation. /// The method symbol and compilation. private static (IMethodSymbol MethodSymbol, Compilation Compilation) GetNonGenericMethodSymbol() { @@ -767,9 +718,7 @@ public void NonGenericMethod() { } return (model.GetDeclaredSymbol(methodDecl)!, compilation); } - /// - /// Gets the resolved method symbol from the first invocation in the source. - /// + /// Gets the resolved method symbol from the first invocation in the source. /// The source code containing an invocation. /// The method symbol and compilation. private static (IMethodSymbol MethodSymbol, Compilation Compilation) GetInvocationMethodSymbol(string source) @@ -813,9 +762,10 @@ void AddReference(System.Reflection.Assembly assembly) AddReference(typeof(object).Assembly); // Add System.Runtime by name - var systemRuntime = AppDomain.CurrentDomain.GetAssemblies() - .FirstOrDefault(a => a.GetName().Name == "System.Runtime"); - if (systemRuntime != null) + var systemRuntime = Array.Find( + AppDomain.CurrentDomain.GetAssemblies(), + static a => a.GetName().Name == "System.Runtime"); + if (systemRuntime is not null) { AddReference(systemRuntime); } diff --git a/src/tests/ReactiveUI.Binding.Analyzer.Tests/Helpers/AnalyzerTestHelper.cs b/src/tests/ReactiveUI.Binding.Analyzer.Tests/Helpers/AnalyzerTestHelper.cs index f12deb2..313dbeb 100644 --- a/src/tests/ReactiveUI.Binding.Analyzer.Tests/Helpers/AnalyzerTestHelper.cs +++ b/src/tests/ReactiveUI.Binding.Analyzer.Tests/Helpers/AnalyzerTestHelper.cs @@ -12,18 +12,14 @@ namespace ReactiveUI.Binding.Analyzer.Tests.Helpers; -/// -/// Helper for testing Roslyn analyzers. -/// +/// Helper for testing Roslyn analyzers. public static class AnalyzerTestHelper { - /// - /// Runs an analyzer on the provided source code and returns diagnostics. - /// + /// Runs an analyzer on the provided source code and returns diagnostics. /// The type of analyzer to run. /// The source code to analyze. /// A task that represents the asynchronous operation. The task result contains the diagnostics. - [SuppressMessage("Minor Code Smell", "S4018:All type parameters should be used in the parameter list to enable type inference", Justification = "Used to infer the type of the analyzer.")] + [SuppressMessage("Design", "SST2307:Type parameter is not inferable", Justification = "the analyzer under test is specified explicitly by the caller")] public static async Task> GetDiagnosticsAsync(string source) where TAnalyzer : DiagnosticAnalyzer, new() { @@ -43,9 +39,7 @@ public static async Task> GetDiagnosticsAsync - /// Creates a CSharpCompilation from the specified source code with required assembly references. - /// + /// Creates a CSharpCompilation from the specified source code with required assembly references. /// The source code to compile into a CSharpCompilation. /// A CSharpCompilation object representing the compiled source code. internal static CSharpCompilation CreateCompilation(string source) @@ -86,8 +80,8 @@ void AddReference(Assembly assembly) var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (var name in assemblyNames) { - var asm = loadedAssemblies.FirstOrDefault(a => a.GetName().Name == name); - if (asm != null) + var asm = System.Array.Find(loadedAssemblies, a => a.GetName().Name == name); + if (asm is not null) { AddReference(asm); } diff --git a/src/tests/ReactiveUI.Binding.Analyzer.Tests/Helpers/TestUtilities.cs b/src/tests/ReactiveUI.Binding.Analyzer.Tests/Helpers/TestUtilities.cs index 8359563..d1bc8bd 100644 --- a/src/tests/ReactiveUI.Binding.Analyzer.Tests/Helpers/TestUtilities.cs +++ b/src/tests/ReactiveUI.Binding.Analyzer.Tests/Helpers/TestUtilities.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding.Analyzer.Tests.Helpers; -/// -/// Utilities for testing analyzers and code fixes. -/// +/// Utilities for testing analyzers and code fixes. public static class TestUtilities { - /// - /// Normalizes whitespace and line endings in source code for comparison. - /// + /// Normalizes whitespace and line endings in source code for comparison. /// The source code to normalize. /// Normalized source code suitable for comparison. public static string NormalizeWhitespace(string source) @@ -20,12 +16,10 @@ public static string NormalizeWhitespace(string source) return string.Join( "\n", source.Split(["\r\n", "\r", "\n"], StringSplitOptions.None) - .Select(line => line.Trim())); + .Select(static line => line.Trim())); } - /// - /// Compares two source code strings with whitespace normalization. - /// + /// Compares two source code strings with whitespace normalization. /// The expected source code. /// The actual source code. /// True if the sources are equivalent after normalization. @@ -37,11 +31,10 @@ public static bool AreEquivalent(string expected, string actual) if (!result) { - Console.WriteLine("=== EXPECTED ==="); - Console.WriteLine(expected); - Console.WriteLine(); - Console.WriteLine("=== ACTUAL ==="); - Console.WriteLine(actual); + // Attach the two sources to the test's own output so a failure is diagnosable from the + // test report; TestContext is null when the helper runs outside a test (e.g. a hook). + TestContext.Current?.OutputWriter.WriteLine( + $"=== EXPECTED ==={Environment.NewLine}{expected}{Environment.NewLine}{Environment.NewLine}=== ACTUAL ==={Environment.NewLine}{actual}"); } return result; diff --git a/src/tests/ReactiveUI.Binding.Analyzer.Tests/TypeAnalyzerTests.cs b/src/tests/ReactiveUI.Binding.Analyzer.Tests/TypeAnalyzerTests.cs index 47f2327..ee83fb2 100644 --- a/src/tests/ReactiveUI.Binding.Analyzer.Tests/TypeAnalyzerTests.cs +++ b/src/tests/ReactiveUI.Binding.Analyzer.Tests/TypeAnalyzerTests.cs @@ -7,14 +7,13 @@ namespace ReactiveUI.Binding.Analyzer.Tests; -/// -/// Tests for . -/// +/// Tests for . public class TypeAnalyzerTests { - /// - /// Common using directives and the generated stub class that the analyzer recognizes. - /// + /// The diagnostic id reported when a type has no observable properties. + private const string NoObservablePropertiesDiagnosticId = "RXUIBIND002"; + + /// Common using directives and the generated stub class that the analyzer recognizes. private const string Preamble = """ using System; using System.ComponentModel; @@ -33,9 +32,7 @@ public static object WhenChanged( } """; - /// - /// Verifies RXUIBIND002 is reported when the source type does not implement any observable mechanism. - /// + /// Verifies RXUIBIND002 is reported when the source type does not implement any observable mechanism. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND002_NoObservableMechanism_ReportsDiagnostic() @@ -62,12 +59,10 @@ public void Test() var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); await Assert.That(diagnostics.Length).IsEqualTo(1); - await Assert.That(diagnostics[0].Id).IsEqualTo("RXUIBIND002"); + await Assert.That(diagnostics[0].Id).IsEqualTo(NoObservablePropertiesDiagnosticId); } - /// - /// Verifies RXUIBIND002 is NOT reported when the source type implements INotifyPropertyChanged. - /// + /// Verifies RXUIBIND002 is NOT reported when the source type implements INotifyPropertyChanged. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND002_INPC_NoDiagnostic() @@ -97,9 +92,7 @@ public void Test() await Assert.That(diagnostics.Length).IsEqualTo(0); } - /// - /// Verifies RXUIBIND002 is NOT reported for empty source code. - /// + /// Verifies RXUIBIND002 is NOT reported for empty source code. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND002_EmptySource_NoDiagnostics() @@ -149,9 +142,7 @@ public void Test() await Assert.That(diagnostics.Length).IsEqualTo(0); } - /// - /// Verifies RXUIBIND002 is NOT reported when the source contains no binding method invocations. - /// + /// Verifies RXUIBIND002 is NOT reported when the source contains no binding method invocations. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND002_NonMethodInvocation_NoDiagnostics() @@ -209,9 +200,7 @@ public void Test() await Assert.That(diagnostics.Length).IsEqualTo(0); } - /// - /// Verifies RXUIBIND002 is NOT reported when the source type implements IReactiveObject. - /// + /// Verifies RXUIBIND002 is NOT reported when the source type implements IReactiveObject. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND002_IReactiveObject_NoDiagnostic() @@ -240,9 +229,7 @@ public void Test() await Assert.That(diagnostics.Length).IsEqualTo(0); } - /// - /// Verifies RXUIBIND002 is NOT reported when the source type inherits from WPF DependencyObject. - /// + /// Verifies RXUIBIND002 is NOT reported when the source type inherits from WPF DependencyObject. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND002_WpfDependencyObject_NoDiagnostic() @@ -276,9 +263,7 @@ public void Test() await Assert.That(diagnostics.Length).IsEqualTo(0); } - /// - /// Verifies RXUIBIND002 is NOT reported when the source type inherits from WinUI DependencyObject. - /// + /// Verifies RXUIBIND002 is NOT reported when the source type inherits from WinUI DependencyObject. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND002_WinUIDependencyObject_NoDiagnostic() @@ -312,9 +297,7 @@ public void Test() await Assert.That(diagnostics.Length).IsEqualTo(0); } - /// - /// Verifies RXUIBIND002 is NOT reported when the source type inherits from Apple NSObject (KVO). - /// + /// Verifies RXUIBIND002 is NOT reported when the source type inherits from Apple NSObject (KVO). /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND002_KVO_NSObject_NoDiagnostic() @@ -348,9 +331,7 @@ public void Test() await Assert.That(diagnostics.Length).IsEqualTo(0); } - /// - /// Verifies RXUIBIND002 is NOT reported when the source type inherits from WinForms Component. - /// + /// Verifies RXUIBIND002 is NOT reported when the source type inherits from WinForms Component. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND002_WinFormsComponent_NoDiagnostic() @@ -384,9 +365,7 @@ public void Test() await Assert.That(diagnostics.Length).IsEqualTo(0); } - /// - /// Verifies RXUIBIND002 is NOT reported when the source type inherits from Android View. - /// + /// Verifies RXUIBIND002 is NOT reported when the source type inherits from Android View. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND002_AndroidView_NoDiagnostic() @@ -456,10 +435,7 @@ public void Test() await Assert.That(diagnostics.Length).IsEqualTo(0); } - /// - /// Verifies RXUIBIND002 IS reported when the source type is an abstract class - /// without any observable mechanism. - /// + /// Verifies RXUIBIND002 IS reported when the source type is an abstract class without any observable mechanism. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND002_AbstractClass_NoObservableMechanism_ReportsDiagnostic() @@ -488,7 +464,7 @@ public void Test() var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); await Assert.That(diagnostics.Length).IsEqualTo(1); - await Assert.That(diagnostics[0].Id).IsEqualTo("RXUIBIND002"); + await Assert.That(diagnostics[0].Id).IsEqualTo(NoObservablePropertiesDiagnosticId); } /// @@ -524,10 +500,7 @@ public void Test() await Assert.That(diagnostics.Length).IsEqualTo(0); } - /// - /// Verifies RXUIBIND002 IS reported when a generic class without any observable mechanism - /// is used as the source type. - /// + /// Verifies RXUIBIND002 IS reported when a generic class without any observable mechanism is used as the source type. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND002_GenericClass_NoObservableMechanism_ReportsDiagnostic() @@ -554,7 +527,7 @@ public void Test() var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); await Assert.That(diagnostics.Length).IsEqualTo(1); - await Assert.That(diagnostics[0].Id).IsEqualTo("RXUIBIND002"); + await Assert.That(diagnostics[0].Id).IsEqualTo(NoObservablePropertiesDiagnosticId); } /// @@ -592,10 +565,7 @@ public void Test() await Assert.That(diagnostics.Length).IsEqualTo(0); } - /// - /// Verifies RXUIBIND002 is NOT reported when the source type inherits INPC from a deep - /// inheritance chain. - /// + /// Verifies RXUIBIND002 is NOT reported when the source type inherits INPC from a deep inheritance chain. /// A task representing the asynchronous test operation. [Test] public async Task RXUIBIND002_DeepInheritanceChain_WithINPC_NoDiagnostic() @@ -934,7 +904,7 @@ public void Test() var diagnostics = await AnalyzerTestHelper.GetDiagnosticsAsync(Source); await Assert.That(diagnostics.Length).IsEqualTo(1); - await Assert.That(diagnostics[0].Id).IsEqualTo("RXUIBIND002"); + await Assert.That(diagnostics[0].Id).IsEqualTo(NoObservablePropertiesDiagnosticId); } /// diff --git a/src/tests/ReactiveUI.Binding.AotValidation/AotChildViewModel.cs b/src/tests/ReactiveUI.Binding.AotValidation/AotChildViewModel.cs index 7bdf53b..b712b0f 100644 --- a/src/tests/ReactiveUI.Binding.AotValidation/AotChildViewModel.cs +++ b/src/tests/ReactiveUI.Binding.AotValidation/AotChildViewModel.cs @@ -6,34 +6,25 @@ namespace ReactiveUI.Binding.AotValidation; -/// -/// A child view model for deep chain AOT validation. -/// +/// A child view model for deep chain AOT validation. public class AotChildViewModel : INotifyPropertyChanged { - /// - /// Backing field for the property, holding the current string value. - /// - private string _value = string.Empty; - /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the value. - /// + /// Gets or sets the value. public string Value { - get => _value; + get => field; set { - if (_value == value) + if (field == value) { return; } - _value = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Value))); } - } + } = string.Empty; } diff --git a/src/tests/ReactiveUI.Binding.AotValidation/AotView.cs b/src/tests/ReactiveUI.Binding.AotValidation/AotView.cs index 81f9c23..0c5260d 100644 --- a/src/tests/ReactiveUI.Binding.AotValidation/AotView.cs +++ b/src/tests/ReactiveUI.Binding.AotValidation/AotView.cs @@ -6,34 +6,25 @@ namespace ReactiveUI.Binding.AotValidation; -/// -/// A view used for AOT binding validation. -/// +/// A view used for AOT binding validation. public class AotView : INotifyPropertyChanged { - /// - /// Backing field for the property, representing the display name of the view. - /// - private string _displayName = string.Empty; - /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the display name. - /// + /// Gets or sets the display name. public string DisplayName { - get => _displayName; + get => field; set { - if (_displayName == value) + if (field == value) { return; } - _displayName = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(DisplayName))); } - } + } = string.Empty; } diff --git a/src/tests/ReactiveUI.Binding.AotValidation/AotViewModel.cs b/src/tests/ReactiveUI.Binding.AotValidation/AotViewModel.cs index df8a080..0ea986f 100644 --- a/src/tests/ReactiveUI.Binding.AotValidation/AotViewModel.cs +++ b/src/tests/ReactiveUI.Binding.AotValidation/AotViewModel.cs @@ -6,87 +6,63 @@ namespace ReactiveUI.Binding.AotValidation; -/// -/// A view model used for AOT validation of source-generated property observation and binding. -/// +/// A view model used for AOT validation of source-generated property observation and binding. public class AotViewModel : INotifyPropertyChanged, INotifyPropertyChanging { - /// - /// Backing field for the property, representing the name associated with the view model. - /// - private string _name = string.Empty; - - /// - /// Backing field for the property, representing the age associated with the view model. - /// - private int _age; - - /// - /// Backing field for the property, representing the associated instance of - /// used for nested view model functionality within the parent . - /// - private AotChildViewModel _child = new(); - /// public event PropertyChangedEventHandler? PropertyChanged; /// public event PropertyChangingEventHandler? PropertyChanging; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { - get => _name; + get => field; set { - if (_name == value) + if (field == value) { return; } PropertyChanging?.Invoke(this, new(nameof(Name))); - _name = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Name))); } - } + } = string.Empty; - /// - /// Gets or sets the age. - /// + /// Gets or sets the age. public int Age { - get => _age; + get => field; set { - if (_age == value) + if (field == value) { return; } PropertyChanging?.Invoke(this, new(nameof(Age))); - _age = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Age))); } } - /// - /// Gets or sets the child view model. - /// + /// Gets or sets the child view model. public AotChildViewModel Child { - get => _child; + get => field; set { - if (_child == value) + if (field == value) { return; } PropertyChanging?.Invoke(this, new(nameof(Child))); - _child = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Child))); } - } + } = new(); } diff --git a/src/tests/ReactiveUI.Binding.AotValidation/Program.cs b/src/tests/ReactiveUI.Binding.AotValidation/Program.cs index 6f40f09..330c562 100644 --- a/src/tests/ReactiveUI.Binding.AotValidation/Program.cs +++ b/src/tests/ReactiveUI.Binding.AotValidation/Program.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for full license information. using System; +using System.IO; namespace ReactiveUI.Binding.AotValidation; @@ -27,17 +28,24 @@ internal static class Program /// The updated age value used to assert change propagation. private const int UpdatedAge = 31; + /// The value set before the binding is disposed, which must survive the disposal. + private const string BeforeDisposal = "Before"; + + /// + /// Sink for scenario results. This validation harness runs standalone under Native AOT with no host + /// or logging infrastructure, so its report goes straight to the process output stream. + /// + private static readonly TextWriter _output = Console.Out; + /// The number of scenarios that have passed. private static int _passed; /// The number of scenarios that have failed. private static int _failed; - /// - /// Runs every AOT binding validation scenario and reports the aggregate result. - /// + /// Runs every AOT binding validation scenario and reports the aggregate result. /// Zero if every scenario passed; otherwise, one. - private static int Main() + internal static int Main() { ValidateWhenChangedSingleProperty(); ValidateWhenChangedDeepChain(); @@ -47,14 +55,12 @@ private static int Main() ValidateBindTwoWay(); ValidateBindOneWayDisposal(); - Console.WriteLine(); - Console.WriteLine($"AOT Validation: {_passed} passed, {_failed} failed"); + Report(string.Empty); + Report($"AOT Validation: {_passed} passed, {_failed} failed"); return _failed > 0 ? 1 : 0; } - /// - /// WhenChanged on a single property emits the initial value and subsequent changes. - /// + /// WhenChanged on a single property emits the initial value and subsequent changes. private static void ValidateWhenChangedSingleProperty() { var vm = new AotViewModel { Name = Alice }; @@ -65,9 +71,7 @@ private static void ValidateWhenChangedSingleProperty() AssertEqual("WhenChanged after set", "Bob", last); } - /// - /// WhenChanged across a deep property chain tracks changes to the leaf value. - /// + /// WhenChanged across a deep property chain tracks changes to the leaf value. private static void ValidateWhenChangedDeepChain() { var vm = new AotViewModel(); @@ -79,9 +83,7 @@ private static void ValidateWhenChangedDeepChain() AssertEqual("WhenChanged deep after set", "Deeper", last); } - /// - /// WhenChanged on two properties emits a tuple and updates when either changes. - /// + /// WhenChanged on two properties emits a tuple and updates when either changes. private static void ValidateWhenChangedTwoProperties() { var vm = new AotViewModel { Name = Alice, Age = InitialAge }; @@ -93,9 +95,7 @@ private static void ValidateWhenChangedTwoProperties() AssertEqual("WhenChanged two-prop age update", UpdatedAge, last.age); } - /// - /// WhenChanged on the view type produces a dispatch entry required by BindTwoWay. - /// + /// WhenChanged on the view type produces a dispatch entry required by BindTwoWay. private static void ValidateWhenChangedOnViewType() { var view = new AotView { DisplayName = "ViewVal" }; @@ -106,9 +106,7 @@ private static void ValidateWhenChangedOnViewType() AssertEqual("WhenChanged on view after set", UpdatedName, last); } - /// - /// BindOneWay propagates source changes to the target property. - /// + /// BindOneWay propagates source changes to the target property. private static void ValidateBindOneWay() { var source = new AotViewModel { Name = SourceName }; @@ -119,9 +117,7 @@ private static void ValidateBindOneWay() AssertEqual("BindOneWay after set", UpdatedName, target.DisplayName); } - /// - /// BindTwoWay propagates changes in both directions between source and target. - /// + /// BindTwoWay propagates changes in both directions between source and target. private static void ValidateBindTwoWay() { var source = new AotViewModel { Name = SourceName }; @@ -134,38 +130,38 @@ private static void ValidateBindTwoWay() AssertEqual("BindTwoWay target→source", "FromTarget", source.Name); } - /// - /// BindOneWay stops propagating once the binding is disposed. - /// + /// BindOneWay stops propagating once the binding is disposed. private static void ValidateBindOneWayDisposal() { - var source = new AotViewModel { Name = "Before" }; + var source = new AotViewModel { Name = BeforeDisposal }; var target = new AotView(); var binding = source.BindOneWay(target, x => x.Name, x => x.DisplayName); - AssertEqual("BindOneWay pre-dispose", "Before", target.DisplayName); + AssertEqual("BindOneWay pre-dispose", BeforeDisposal, target.DisplayName); binding.Dispose(); source.Name = "After"; - AssertEqual("BindOneWay post-dispose unchanged", "Before", target.DisplayName); + AssertEqual("BindOneWay post-dispose unchanged", BeforeDisposal, target.DisplayName); } - /// - /// Compares an expected and actual value, recording a pass or failure to the console. - /// + /// Compares an expected and actual value, recording a pass or failure to the console. /// The value type being compared. /// A human-readable label for the scenario. /// The expected value. /// The actual value produced by the binding. private static void AssertEqual(string label, T expected, T? actual) { - if (Equals(expected, actual)) + if (EqualityComparer.Default.Equals(expected, actual)) { - Console.WriteLine($" PASS: {label}"); + Report($" PASS: {label}"); _passed++; } else { - Console.WriteLine($" FAIL: {label} — expected '{expected}', got '{actual}'"); + Report($" FAIL: {label} - expected '{expected}', got '{actual}'"); _failed++; } } + + /// Writes a single line of the validation report to the process output stream. + /// The line to write. + private static void Report(string message) => _output.WriteLine(message); } diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/BindCommandScenarios.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/BindCommandScenarios.cs index ffcfe09..acd9390 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/BindCommandScenarios.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/BindCommandScenarios.cs @@ -12,31 +12,25 @@ namespace ReactiveUI.Binding.GeneratedCode.TestModels.Scenarios; /// public static class BindCommandScenarios { - /// - /// Binds the Save command to the SaveButton's Click event with no parameter. - /// + /// Binds the Save command to the SaveButton's Click event with no parameter. /// The source view model. /// The target view. /// A disposable representing the binding. public static IDisposable BasicNoParam( SharedScenarios.BindCommand.BasicNoParam.MyViewModel vm, - SharedScenarios.BindCommand.BasicNoParam.MyView view) - => SharedScenarios.BindCommand.BasicNoParam.Scenario.Execute(vm, view); + SharedScenarios.BindCommand.BasicNoParam.MyView view) => + SharedScenarios.BindCommand.BasicNoParam.Scenario.Execute(vm, view); - /// - /// Binds the Save command with an expression-based parameter from the VM. - /// + /// Binds the Save command with an expression-based parameter from the VM. /// The source view model. /// The target view. /// A disposable representing the binding. public static IDisposable ExpressionParam( SharedScenarios.BindCommand.ExpressionParam.MyViewModel vm, - SharedScenarios.BindCommand.ExpressionParam.MyView view) - => SharedScenarios.BindCommand.ExpressionParam.Scenario.Execute(vm, view); + SharedScenarios.BindCommand.ExpressionParam.MyView view) => + SharedScenarios.BindCommand.ExpressionParam.Scenario.Execute(vm, view); - /// - /// Binds the Save command with an observable parameter. - /// + /// Binds the Save command with an observable parameter. /// The source view model. /// The target view. /// An observable producing command parameters. @@ -44,42 +38,35 @@ public static IDisposable ExpressionParam( public static IDisposable ObservableParam( SharedScenarios.BindCommand.ObservableParam.MyViewModel vm, SharedScenarios.BindCommand.ObservableParam.MyView view, - IObservable parameter) - => SharedScenarios.BindCommand.ObservableParam.Scenario.Execute(vm, view, parameter); + IObservable parameter) => + SharedScenarios.BindCommand.ObservableParam.Scenario.Execute(vm, view, parameter); - /// - /// Binds the Save command to the SaveButton's MouseUp event via explicit toEvent. - /// + /// Binds the Save command to the SaveButton's MouseUp event via explicit toEvent. /// The source view model. /// The target view. /// A disposable representing the binding. public static IDisposable CustomEvent( SharedScenarios.BindCommand.CustomEvent.MyViewModel vm, - SharedScenarios.BindCommand.CustomEvent.MyView view) - => SharedScenarios.BindCommand.CustomEvent.Scenario.Execute(vm, view); + SharedScenarios.BindCommand.CustomEvent.MyView view) => + SharedScenarios.BindCommand.CustomEvent.Scenario.Execute(vm, view); - /// - /// Binds the Child.SaveCommand to the SaveButton's Click event via a deep command path. - /// + /// Binds the Child.SaveCommand to the SaveButton's Click event via a deep command path. /// The source view model. /// The target view. /// A disposable representing the binding. public static IDisposable DeepCommandPath( SharedScenarios.BindCommand.DeepCommandPath.MyViewModel vm, - SharedScenarios.BindCommand.DeepCommandPath.MyView view) - => SharedScenarios.BindCommand.DeepCommandPath.Scenario.Execute(vm, view); + SharedScenarios.BindCommand.DeepCommandPath.MyView view) => + SharedScenarios.BindCommand.DeepCommandPath.Scenario.Execute(vm, view); - /// - /// Binds the Save command via Click+Enabled (no Command property, no parameter). - /// Routes through EventEnabledBindingPlugin. - /// + /// Binds the Save command via Click+Enabled (no Command property, no parameter). Routes through EventEnabledBindingPlugin. /// The source view model. /// The target view. /// A disposable representing the binding. public static IDisposable EventEnabled( SharedScenarios.BindCommand.EventEnabled.MyViewModel vm, - SharedScenarios.BindCommand.EventEnabled.MyView view) - => SharedScenarios.BindCommand.EventEnabled.Scenario.Execute(vm, view); + SharedScenarios.BindCommand.EventEnabled.MyView view) => + SharedScenarios.BindCommand.EventEnabled.Scenario.Execute(vm, view); /// /// Binds the Save command via Click+Enabled with an expression parameter. @@ -90,8 +77,8 @@ public static IDisposable EventEnabled( /// A disposable representing the binding. public static IDisposable EventEnabledExprParam( SharedScenarios.BindCommand.EventEnabledExprParam.MyViewModel vm, - SharedScenarios.BindCommand.EventEnabledExprParam.MyView view) - => SharedScenarios.BindCommand.EventEnabledExprParam.Scenario.Execute(vm, view); + SharedScenarios.BindCommand.EventEnabledExprParam.MyView view) => + SharedScenarios.BindCommand.EventEnabledExprParam.Scenario.Execute(vm, view); /// /// Binds the Save command via Click+Enabled with an observable parameter. @@ -104,20 +91,17 @@ public static IDisposable EventEnabledExprParam( public static IDisposable EventEnabledObsParam( SharedScenarios.BindCommand.EventEnabledObsParam.MyViewModel vm, SharedScenarios.BindCommand.EventEnabledObsParam.MyView view, - IObservable parameter) - => SharedScenarios.BindCommand.EventEnabledObsParam.Scenario.Execute(vm, view, parameter); + IObservable parameter) => + SharedScenarios.BindCommand.EventEnabledObsParam.Scenario.Execute(vm, view, parameter); - /// - /// Binds the Save command via Command property (no event, no parameter). - /// Routes through CommandPropertyBindingPlugin. - /// + /// Binds the Save command via Command property (no event, no parameter). Routes through CommandPropertyBindingPlugin. /// The source view model. /// The target view. /// A disposable representing the binding. public static IDisposable CommandProperty( SharedScenarios.BindCommand.CommandProperty.MyViewModel vm, - SharedScenarios.BindCommand.CommandProperty.MyView view) - => SharedScenarios.BindCommand.CommandProperty.Scenario.Execute(vm, view); + SharedScenarios.BindCommand.CommandProperty.MyView view) => + SharedScenarios.BindCommand.CommandProperty.Scenario.Execute(vm, view); /// /// Binds the Save command via Command property with an expression parameter. @@ -128,8 +112,8 @@ public static IDisposable CommandProperty( /// A disposable representing the binding. public static IDisposable CommandPropertyExprParam( SharedScenarios.BindCommand.CommandPropertyExprParam.MyViewModel vm, - SharedScenarios.BindCommand.CommandPropertyExprParam.MyView view) - => SharedScenarios.BindCommand.CommandPropertyExprParam.Scenario.Execute(vm, view); + SharedScenarios.BindCommand.CommandPropertyExprParam.MyView view) => + SharedScenarios.BindCommand.CommandPropertyExprParam.Scenario.Execute(vm, view); /// /// Binds the Save command via Command property with an observable parameter. @@ -142,18 +126,15 @@ public static IDisposable CommandPropertyExprParam( public static IDisposable CommandPropertyObsParam( SharedScenarios.BindCommand.CommandPropertyObsParam.MyViewModel vm, SharedScenarios.BindCommand.CommandPropertyObsParam.MyView view, - IObservable parameter) - => SharedScenarios.BindCommand.CommandPropertyObsParam.Scenario.Execute(vm, view, parameter); + IObservable parameter) => + SharedScenarios.BindCommand.CommandPropertyObsParam.Scenario.Execute(vm, view, parameter); - /// - /// Binds the Save command to a control with no default event. - /// Falls back to runtime command binding service. - /// + /// Binds the Save command to a control with no default event. Falls back to runtime command binding service. /// The source view model. /// The target view. /// A disposable representing the binding. public static IDisposable NoEvent( SharedScenarios.BindCommand.NoEvent.MyViewModel vm, - SharedScenarios.BindCommand.NoEvent.MyView view) - => SharedScenarios.BindCommand.NoEvent.Scenario.Execute(vm, view); + SharedScenarios.BindCommand.NoEvent.MyView view) => + SharedScenarios.BindCommand.NoEvent.Scenario.Execute(vm, view); } diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/BindCompatScenarios.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/BindCompatScenarios.cs index 024c2eb..7ae7d9b 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/BindCompatScenarios.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/BindCompatScenarios.cs @@ -6,19 +6,15 @@ namespace ReactiveUI.Binding.GeneratedCode.TestModels.Scenarios; -/// -/// Scenario methods for Bind (view-first two-way compat alias) that the source generator processes at compile time. -/// +/// Scenario methods for Bind (view-first two-way compat alias) that the source generator processes at compile time. public static class BindCompatScenarios { - /// - /// View-first two-way binding for a string property using the Bind compat alias. - /// + /// View-first two-way binding for a string property using the Bind compat alias. /// The target view. /// The source view model. /// A reactive binding representing the binding. - public static IReactiveBinding StringProperty( + public static IReactiveBinding StringProperty( TestView view, - TestViewModel vm) - => view.Bind(vm, x => x.Name, x => x.DisplayName); + TestViewModel vm) => + view.Bind(vm, x => x.Name, x => x.DisplayName); } diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/BindInteractionScenarios.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/BindInteractionScenarios.cs index 3622b4b..1ced612 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/BindInteractionScenarios.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/BindInteractionScenarios.cs @@ -12,36 +12,30 @@ namespace ReactiveUI.Binding.GeneratedCode.TestModels.Scenarios; /// public static class BindInteractionScenarios { - /// - /// Binds a task-based handler that always sets output to . - /// + /// Binds a task-based handler that always sets output to . /// The source view model. /// The target view. /// A disposable representing the binding. public static IDisposable TaskHandler( SharedScenarios.BindInteraction.TaskHandler.MyViewModel vm, - SharedScenarios.BindInteraction.TaskHandler.MyView view) - => SharedScenarios.BindInteraction.TaskHandler.Scenario.Execute(vm, view); + SharedScenarios.BindInteraction.TaskHandler.MyView view) => + SharedScenarios.BindInteraction.TaskHandler.Scenario.Execute(vm, view); - /// - /// Binds an observable-based handler that always sets output to . - /// + /// Binds an observable-based handler that always sets output to . /// The source view model. /// The target view. /// A disposable representing the binding. public static IDisposable ObservableHandler( SharedScenarios.BindInteraction.ObservableHandler.MyViewModel vm, - SharedScenarios.BindInteraction.ObservableHandler.MyView view) - => SharedScenarios.BindInteraction.ObservableHandler.Scenario.Execute(vm, view); + SharedScenarios.BindInteraction.ObservableHandler.MyView view) => + SharedScenarios.BindInteraction.ObservableHandler.Scenario.Execute(vm, view); - /// - /// Binds a task-based handler to a deep property path (nested interaction). - /// + /// Binds a task-based handler to a deep property path (nested interaction). /// The source view model. /// The target view. /// A disposable representing the binding. public static IDisposable DeepPropertyPath( SharedScenarios.BindInteraction.DeepPropertyPath.MyViewModel vm, - SharedScenarios.BindInteraction.DeepPropertyPath.MyView view) - => SharedScenarios.BindInteraction.DeepPropertyPath.Scenario.Execute(vm, view); + SharedScenarios.BindInteraction.DeepPropertyPath.MyView view) => + SharedScenarios.BindInteraction.DeepPropertyPath.Scenario.Execute(vm, view); } diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/BindOneWayScenarios.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/BindOneWayScenarios.cs index d0d9abc..cdfb166 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/BindOneWayScenarios.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/BindOneWayScenarios.cs @@ -13,57 +13,45 @@ namespace ReactiveUI.Binding.GeneratedCode.TestModels.Scenarios; /// public static class BindOneWayScenarios { - /// - /// One-way binding for a string property. - /// + /// One-way binding for a string property. /// The source view model. /// The target view. /// A disposable that, when disposed, disconnects the binding. - public static IDisposable StringProperty(BigViewModel source, BigView target) - => source.BindOneWay(target, x => x.Prop1, x => x.ViewProp1); + public static IDisposable StringProperty(BigViewModel source, BigView target) => + source.BindOneWay(target, x => x.Prop1, x => x.ViewProp1); - /// - /// One-way binding for an int property. - /// + /// One-way binding for an int property. /// The source view model. /// The target view. /// A disposable that, when disposed, disconnects the binding. - public static IDisposable IntProperty(BigViewModel source, BigView target) - => source.BindOneWay(target, x => x.Prop2, x => x.ViewProp2); + public static IDisposable IntProperty(BigViewModel source, BigView target) => + source.BindOneWay(target, x => x.Prop2, x => x.ViewProp2); - /// - /// One-way binding for a double property. - /// + /// One-way binding for a double property. /// The source view model. /// The target view. /// A disposable that, when disposed, disconnects the binding. - public static IDisposable DoubleProperty(BigViewModel source, BigView target) - => source.BindOneWay(target, x => x.Prop3, x => x.ViewProp3); + public static IDisposable DoubleProperty(BigViewModel source, BigView target) => + source.BindOneWay(target, x => x.Prop3, x => x.ViewProp3); - /// - /// One-way binding for a bool property. - /// + /// One-way binding for a bool property. /// The source view model. /// The target view. /// A disposable that, when disposed, disconnects the binding. - public static IDisposable BoolProperty(BigViewModel source, BigView target) - => source.BindOneWay(target, x => x.Prop4, x => x.ViewProp4); + public static IDisposable BoolProperty(BigViewModel source, BigView target) => + source.BindOneWay(target, x => x.Prop4, x => x.ViewProp4); - /// - /// One-way binding with a deep chain source property (Address.City). - /// + /// One-way binding with a deep chain source property (Address.City). /// The source view model. /// The target view. /// A disposable that, when disposed, disconnects the binding. - public static IDisposable DeepChainProperty(BigViewModel source, BigView target) - => source.BindOneWay(target, x => x.Address.City, x => x.ViewProp1); + public static IDisposable DeepChainProperty(BigViewModel source, BigView target) => + source.BindOneWay(target, x => x.Address.City, x => x.ViewProp1); - /// - /// One-way binding for a second string property (for multiple binding tests). - /// + /// One-way binding for a second string property (for multiple binding tests). /// The source view model. /// The target view. /// A disposable that, when disposed, disconnects the binding. - public static IDisposable StringProperty5(BigViewModel source, BigView target) - => source.BindOneWay(target, x => x.Prop5, x => x.ViewProp5); + public static IDisposable StringProperty5(BigViewModel source, BigView target) => + source.BindOneWay(target, x => x.Prop5, x => x.ViewProp5); } diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/BindToScenarios.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/BindToScenarios.cs index 02142be..7e3fd7c 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/BindToScenarios.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/BindToScenarios.cs @@ -7,17 +7,13 @@ namespace ReactiveUI.Binding.GeneratedCode.TestModels.Scenarios; -/// -/// Scenario methods for BindTo that the source generator processes at compile time. -/// +/// Scenario methods for BindTo that the source generator processes at compile time. public static class BindToScenarios { - /// - /// Binds a string observable stream to a same-typed string property (direct assignment). - /// + /// Binds a string observable stream to a same-typed string property (direct assignment). /// The source observable stream. /// The target view. /// A disposable that, when disposed, disconnects the binding. - public static IDisposable StringToString(IObservable source, BigView target) - => source.BindTo(target, x => x.ViewProp1); + public static IDisposable StringToString(IObservable source, BigView target) => + source.BindTo(target, x => x.ViewProp1); } diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/BindTwoWayScenarios.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/BindTwoWayScenarios.cs index c7b5924..8b2aea0 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/BindTwoWayScenarios.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/BindTwoWayScenarios.cs @@ -13,39 +13,31 @@ namespace ReactiveUI.Binding.GeneratedCode.TestModels.Scenarios; /// public static class BindTwoWayScenarios { - /// - /// Two-way binding for a string property. - /// + /// Two-way binding for a string property. /// The source view model. /// The target view. /// A disposable that, when disposed, disconnects the binding. - public static IDisposable StringProperty(BigViewModel source, BigView target) - => source.BindTwoWay(target, x => x.Prop1, x => x.ViewProp1); + public static IDisposable StringProperty(BigViewModel source, BigView target) => + source.BindTwoWay(target, x => x.Prop1, x => x.ViewProp1); - /// - /// Two-way binding for an int property. - /// + /// Two-way binding for an int property. /// The source view model. /// The target view. /// A disposable that, when disposed, disconnects the binding. - public static IDisposable IntProperty(BigViewModel source, BigView target) - => source.BindTwoWay(target, x => x.Prop2, x => x.ViewProp2); + public static IDisposable IntProperty(BigViewModel source, BigView target) => + source.BindTwoWay(target, x => x.Prop2, x => x.ViewProp2); - /// - /// Two-way binding for a double property. - /// + /// Two-way binding for a double property. /// The source view model. /// The target view. /// A disposable that, when disposed, disconnects the binding. - public static IDisposable DoubleProperty(BigViewModel source, BigView target) - => source.BindTwoWay(target, x => x.Prop3, x => x.ViewProp3); + public static IDisposable DoubleProperty(BigViewModel source, BigView target) => + source.BindTwoWay(target, x => x.Prop3, x => x.ViewProp3); - /// - /// Two-way binding for a bool property. - /// + /// Two-way binding for a bool property. /// The source view model. /// The target view. /// A disposable that, when disposed, disconnects the binding. - public static IDisposable BoolProperty(BigViewModel source, BigView target) - => source.BindTwoWay(target, x => x.Prop4, x => x.ViewProp4); + public static IDisposable BoolProperty(BigViewModel source, BigView target) => + source.BindTwoWay(target, x => x.Prop4, x => x.ViewProp4); } diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/OneWayBindCompatScenarios.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/OneWayBindCompatScenarios.cs index 87acf8c..b116ac5 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/OneWayBindCompatScenarios.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/OneWayBindCompatScenarios.cs @@ -6,17 +6,13 @@ namespace ReactiveUI.Binding.GeneratedCode.TestModels.Scenarios; -/// -/// Scenario methods for OneWayBind (view-first compat alias) that the source generator processes at compile time. -/// +/// Scenario methods for OneWayBind (view-first compat alias) that the source generator processes at compile time. public static class OneWayBindCompatScenarios { - /// - /// View-first one-way binding for a string property using the OneWayBind compat alias. - /// + /// View-first one-way binding for a string property using the OneWayBind compat alias. /// The target view. /// The source view model. /// A reactive binding representing the binding. - public static IReactiveBinding StringProperty(TestView view, TestViewModel vm) - => view.OneWayBind(vm, x => x.Name, x => x.DisplayName); + public static IReactiveBinding StringProperty(TestView view, TestViewModel vm) => + view.OneWayBind(vm, x => x.Name, x => x.DisplayName); } diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenAnyObservableScenarios.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenAnyObservableScenarios.cs index 3c1820c..31235ef 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenAnyObservableScenarios.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenAnyObservableScenarios.cs @@ -13,19 +13,15 @@ namespace ReactiveUI.Binding.GeneratedCode.TestModels.Scenarios; /// public static class WhenAnyObservableScenarios { - /// - /// Single observable property observation using Switch pattern. - /// + /// Single observable property observation using Switch pattern. /// The view model to observe. /// An observable that switches to the latest MyCommand observable. - public static IObservable SingleObservable_Switch(ObservablePropertyViewModel vm) - => vm.WhenAnyObservable(x => x.MyCommand); + public static IObservable SingleObservable_Switch(ObservablePropertyViewModel vm) => + vm.WhenAnyObservable(x => x.MyCommand); - /// - /// Two observable properties of the same type using Merge pattern. - /// + /// Two observable properties of the same type using Merge pattern. /// The view model to observe. /// An observable that merges both command observables. - public static IObservable TwoObservables_Merge(ObservablePropertyViewModel vm) - => vm.WhenAnyObservable(x => x.MyCommand, x => x.OtherCommand); + public static IObservable TwoObservables_Merge(ObservablePropertyViewModel vm) => + vm.WhenAnyObservable(x => x.MyCommand, x => x.OtherCommand); } diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenAnyScenarios.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenAnyScenarios.cs index 7166093..4645181 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenAnyScenarios.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenAnyScenarios.cs @@ -13,28 +13,22 @@ namespace ReactiveUI.Binding.GeneratedCode.TestModels.Scenarios; /// public static class WhenAnyScenarios { - /// - /// Single property WhenAny observation with a selector extracting the value. - /// + /// Single property WhenAny observation with a selector extracting the value. /// The view model to observe. /// An observable of the Name property value. - public static IObservable SingleProperty_Name(TestViewModel vm) - => vm.WhenAny(x => x.Name, c => c.Value); + public static IObservable SingleProperty_Name(TestViewModel vm) => + vm.WhenAny(x => x.Name, static c => c.Value); - /// - /// Single property WhenAny observation returning the IObservedChange directly. - /// + /// Single property WhenAny observation returning the IObservedChange directly. /// The view model to observe. /// An observable of IObservedChange for the Name property. public static IObservable> SingleProperty_Name_ObservedChange( - TestViewModel vm) - => vm.WhenAny(x => x.Name, c => c); + TestViewModel vm) => + vm.WhenAny(x => x.Name, static c => c); - /// - /// Two-property WhenAny observation with a selector combining values. - /// + /// Two-property WhenAny observation with a selector combining values. /// The view model to observe. /// An observable of the combined name and age string. - public static IObservable TwoProperties_NameAge(TestViewModel vm) - => vm.WhenAny(x => x.Name, x => x.Age, (name, age) => $"{name.Value}_{age.Value}"); + public static IObservable TwoProperties_NameAge(TestViewModel vm) => + vm.WhenAny(x => x.Name, x => x.Age, static (name, age) => $"{name.Value}_{age.Value}"); } diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenAnyValueExtendedScenarios.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenAnyValueExtendedScenarios.cs index bcdf6fe..a4295f4 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenAnyValueExtendedScenarios.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenAnyValueExtendedScenarios.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for full license information. using System; -using System.Diagnostics.CodeAnalysis; using ReactiveUI.Binding.GeneratedCode.TestModels.TestModels; namespace ReactiveUI.Binding.GeneratedCode.TestModels.Scenarios; @@ -12,49 +11,37 @@ namespace ReactiveUI.Binding.GeneratedCode.TestModels.Scenarios; /// Extended scenario methods for WhenAnyValue that exercise the 4-16 property overloads. /// Each method exercises a specific WhenAnyValue overload at compile time. /// -[SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "These scenarios intentionally exercise the high-arity (8-16 property) overloads; the selector lambda parameter counts are inherent to the overloads under test.")] public static class WhenAnyValueExtendedScenarios { - /// - /// Four-property observation using WhenAnyValue returning a tuple. - /// + /// Four-property observation using WhenAnyValue returning a tuple. /// The view model to observe. /// An observable of the property value tuple. public static IObservable<(string property1, int property2, double property3, bool property4)> FourProperties( - BigViewModel vm) - => vm.WhenAnyValue(x => x.Prop1, x => x.Prop2, x => x.Prop3, x => x.Prop4); + BigViewModel vm) => + vm.WhenAnyValue(x => x.Prop1, x => x.Prop2, x => x.Prop3, x => x.Prop4); - /// - /// Five-property observation using WhenAnyValue returning a tuple. - /// + /// Five-property observation using WhenAnyValue returning a tuple. /// The view model to observe. /// An observable of the property value tuple. public static IObservable<(string property1, int property2, double property3, bool property4, string property5)> - FiveProperties(BigViewModel vm) - => vm.WhenAnyValue(x => x.Prop1, x => x.Prop2, x => x.Prop3, x => x.Prop4, x => x.Prop5); + FiveProperties(BigViewModel vm) => + vm.WhenAnyValue(x => x.Prop1, x => x.Prop2, x => x.Prop3, x => x.Prop4, x => x.Prop5); - /// - /// Six-property observation using WhenAnyValue returning a tuple. - /// + /// Six-property observation using WhenAnyValue returning a tuple. /// The view model to observe. /// An observable of the property value tuple. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6)> - SixProperties(BigViewModel vm) - => vm.WhenAnyValue(x => x.Prop1, x => x.Prop2, x => x.Prop3, x => x.Prop4, x => x.Prop5, x => x.Prop6); + SixProperties(BigViewModel vm) => + vm.WhenAnyValue(x => x.Prop1, x => x.Prop2, x => x.Prop3, x => x.Prop4, x => x.Prop5, x => x.Prop6); - /// - /// Seven-property observation using WhenAnyValue returning a tuple. - /// + /// Seven-property observation using WhenAnyValue returning a tuple. /// The view model to observe. /// An observable of the property value tuple. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, - double property7)> SevenProperties(BigViewModel vm) - => vm.WhenAnyValue( + double property7)> SevenProperties(BigViewModel vm) => + vm.WhenAnyValue( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -63,15 +50,13 @@ public static x => x.Prop6, x => x.Prop7); - /// - /// Eight-property observation using WhenAnyValue returning a tuple. - /// + /// Eight-property observation using WhenAnyValue returning a tuple. /// The view model to observe. /// An observable of the property value tuple. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, - double property7, bool property8)> EightProperties(BigViewModel vm) - => vm.WhenAnyValue( + double property7, bool property8)> EightProperties(BigViewModel vm) => + vm.WhenAnyValue( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -81,15 +66,13 @@ public static x => x.Prop7, x => x.Prop8); - /// - /// Nine-property observation using WhenAnyValue returning a tuple. - /// + /// Nine-property observation using WhenAnyValue returning a tuple. /// The view model to observe. /// An observable of the property value tuple. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, - double property7, bool property8, string property9)> NineProperties(BigViewModel vm) - => vm.WhenAnyValue( + double property7, bool property8, string property9)> NineProperties(BigViewModel vm) => + vm.WhenAnyValue( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -100,15 +83,13 @@ public static x => x.Prop8, x => x.Prop9); - /// - /// Ten-property observation using WhenAnyValue returning a tuple. - /// + /// Ten-property observation using WhenAnyValue returning a tuple. /// The view model to observe. /// An observable of the property value tuple. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, - double property7, bool property8, string property9, int property10)> TenProperties(BigViewModel vm) - => vm.WhenAnyValue( + double property7, bool property8, string property9, int property10)> TenProperties(BigViewModel vm) => + vm.WhenAnyValue( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -120,16 +101,14 @@ public static x => x.Prop9, x => x.Prop10); - /// - /// Eleven-property observation using WhenAnyValue returning a tuple. - /// + /// Eleven-property observation using WhenAnyValue returning a tuple. /// The view model to observe. /// An observable of the property value tuple. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, double property7, bool property8, string property9, int property10, double property11)> ElevenProperties( - BigViewModel vm) - => vm.WhenAnyValue( + BigViewModel vm) => + vm.WhenAnyValue( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -142,16 +121,14 @@ public static x => x.Prop10, x => x.Prop11); - /// - /// Twelve-property observation using WhenAnyValue returning a tuple. - /// + /// Twelve-property observation using WhenAnyValue returning a tuple. /// The view model to observe. /// An observable of the property value tuple. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, double property7, bool property8, string property9, int property10, double property11, bool property12)> - TwelveProperties(BigViewModel vm) - => vm.WhenAnyValue( + TwelveProperties(BigViewModel vm) => + vm.WhenAnyValue( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -165,15 +142,13 @@ public static x => x.Prop11, x => x.Prop12); - /// - /// Thirteen-property observation using WhenAnyValue returning a tuple. - /// + /// Thirteen-property observation using WhenAnyValue returning a tuple. /// The view model to observe. /// An observable of the property value tuple. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, double property7, bool property8, string property9, int property10, double property11, bool - property12, string property13)> ThirteenProperties(BigViewModel vm) - => vm.WhenAnyValue( + property12, string property13)> ThirteenProperties(BigViewModel vm) => + vm.WhenAnyValue( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -188,15 +163,13 @@ public static x => x.Prop12, x => x.Prop13); - /// - /// Fourteen-property observation using WhenAnyValue returning a tuple. - /// + /// Fourteen-property observation using WhenAnyValue returning a tuple. /// The view model to observe. /// An observable of the property value tuple. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, double property7, bool property8, string property9, int property10, double property11, bool - property12, string property13, int property14)> FourteenProperties(BigViewModel vm) - => vm.WhenAnyValue( + property12, string property13, int property14)> FourteenProperties(BigViewModel vm) => + vm.WhenAnyValue( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -212,15 +185,13 @@ public static x => x.Prop13, x => x.Prop14); - /// - /// Fifteen-property observation using WhenAnyValue returning a tuple. - /// + /// Fifteen-property observation using WhenAnyValue returning a tuple. /// The view model to observe. /// An observable of the property value tuple. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, double property7, bool property8, string property9, int property10, double property11, bool - property12, string property13, int property14, double property15)> FifteenProperties(BigViewModel vm) - => vm.WhenAnyValue( + property12, string property13, int property14, double property15)> FifteenProperties(BigViewModel vm) => + vm.WhenAnyValue( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -237,16 +208,14 @@ public static x => x.Prop14, x => x.Prop15); - /// - /// Sixteen-property observation using WhenAnyValue returning a tuple. - /// + /// Sixteen-property observation using WhenAnyValue returning a tuple. /// The view model to observe. /// An observable of the property value tuple. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, double property7, bool property8, string property9, int property10, double property11, bool property12, string property13, int property14, double property15, bool property16)> SixteenProperties( - BigViewModel vm) - => vm.WhenAnyValue( + BigViewModel vm) => + vm.WhenAnyValue( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -264,55 +233,47 @@ public static x => x.Prop15, x => x.Prop16); - /// - /// Four-property observation with a selector using WhenAnyValue. - /// + /// Four-property observation with a selector using WhenAnyValue. /// The view model to observe. /// An observable of the combined string value. - public static IObservable WithSelector_FourProperties(BigViewModel vm) - => vm.WhenAnyValue( + public static IObservable WithSelector_FourProperties(BigViewModel vm) => + vm.WhenAnyValue( x => x.Prop1, x => x.Prop2, x => x.Prop3, x => x.Prop4, - (p1, p2, p3, p4) => $"{p1}_{p2}_{p3}_{p4}"); + static (p1, p2, p3, p4) => $"{p1}_{p2}_{p3}_{p4}"); - /// - /// Five-property observation with a selector using WhenAnyValue. - /// + /// Five-property observation with a selector using WhenAnyValue. /// The view model to observe. /// An observable of the combined string value. - public static IObservable WithSelector_FiveProperties(BigViewModel vm) - => vm.WhenAnyValue( + public static IObservable WithSelector_FiveProperties(BigViewModel vm) => + vm.WhenAnyValue( x => x.Prop1, x => x.Prop2, x => x.Prop3, x => x.Prop4, x => x.Prop5, - (p1, p2, p3, p4, p5) => $"{p1}_{p2}_{p3}_{p4}_{p5}"); + static (p1, p2, p3, p4, p5) => $"{p1}_{p2}_{p3}_{p4}_{p5}"); - /// - /// Six-property observation with a selector using WhenAnyValue. - /// + /// Six-property observation with a selector using WhenAnyValue. /// The view model to observe. /// An observable of the combined string value. - public static IObservable WithSelector_SixProperties(BigViewModel vm) - => vm.WhenAnyValue( + public static IObservable WithSelector_SixProperties(BigViewModel vm) => + vm.WhenAnyValue( x => x.Prop1, x => x.Prop2, x => x.Prop3, x => x.Prop4, x => x.Prop5, x => x.Prop6, - (p1, p2, p3, p4, p5, p6) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}"); + static (p1, p2, p3, p4, p5, p6) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}"); - /// - /// Seven-property observation with a selector using WhenAnyValue. - /// + /// Seven-property observation with a selector using WhenAnyValue. /// The view model to observe. /// An observable of the combined string value. - public static IObservable WithSelector_SevenProperties(BigViewModel vm) - => vm.WhenAnyValue( + public static IObservable WithSelector_SevenProperties(BigViewModel vm) => + vm.WhenAnyValue( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -320,15 +281,13 @@ public static IObservable WithSelector_SevenProperties(BigViewModel vm) x => x.Prop5, x => x.Prop6, x => x.Prop7, - (p1, p2, p3, p4, p5, p6, p7) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}"); + static (p1, p2, p3, p4, p5, p6, p7) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}"); - /// - /// Eight-property observation with a selector using WhenAnyValue. - /// + /// Eight-property observation with a selector using WhenAnyValue. /// The view model to observe. /// An observable of the combined string value. - public static IObservable WithSelector_EightProperties(BigViewModel vm) - => vm.WhenAnyValue( + public static IObservable WithSelector_EightProperties(BigViewModel vm) => + vm.WhenAnyValue( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -337,15 +296,13 @@ public static IObservable WithSelector_EightProperties(BigViewModel vm) x => x.Prop6, x => x.Prop7, x => x.Prop8, - (p1, p2, p3, p4, p5, p6, p7, p8) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}"); + static (p1, p2, p3, p4, p5, p6, p7, p8) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}"); - /// - /// Nine-property observation with a selector using WhenAnyValue. - /// + /// Nine-property observation with a selector using WhenAnyValue. /// The view model to observe. /// An observable of the combined string value. - public static IObservable WithSelector_NineProperties(BigViewModel vm) - => vm.WhenAnyValue( + public static IObservable WithSelector_NineProperties(BigViewModel vm) => + vm.WhenAnyValue( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -355,15 +312,13 @@ public static IObservable WithSelector_NineProperties(BigViewModel vm) x => x.Prop7, x => x.Prop8, x => x.Prop9, - (p1, p2, p3, p4, p5, p6, p7, p8, p9) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}"); + static (p1, p2, p3, p4, p5, p6, p7, p8, p9) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}"); - /// - /// Ten-property observation with a selector using WhenAnyValue. - /// + /// Ten-property observation with a selector using WhenAnyValue. /// The view model to observe. /// An observable of the combined string value. - public static IObservable WithSelector_TenProperties(BigViewModel vm) - => vm.WhenAnyValue( + public static IObservable WithSelector_TenProperties(BigViewModel vm) => + vm.WhenAnyValue( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -374,15 +329,13 @@ public static IObservable WithSelector_TenProperties(BigViewModel vm) x => x.Prop8, x => x.Prop9, x => x.Prop10, - (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}_{p10}"); + static (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}_{p10}"); - /// - /// Eleven-property observation with a selector using WhenAnyValue. - /// + /// Eleven-property observation with a selector using WhenAnyValue. /// The view model to observe. /// An observable of the combined string value. - public static IObservable WithSelector_ElevenProperties(BigViewModel vm) - => vm.WhenAnyValue( + public static IObservable WithSelector_ElevenProperties(BigViewModel vm) => + vm.WhenAnyValue( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -394,16 +347,14 @@ public static IObservable WithSelector_ElevenProperties(BigViewModel vm) x => x.Prop9, x => x.Prop10, x => x.Prop11, - (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) => + static (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}_{p10}_{p11}"); - /// - /// Twelve-property observation with a selector using WhenAnyValue. - /// + /// Twelve-property observation with a selector using WhenAnyValue. /// The view model to observe. /// An observable of the combined string value. - public static IObservable WithSelector_TwelveProperties(BigViewModel vm) - => vm.WhenAnyValue( + public static IObservable WithSelector_TwelveProperties(BigViewModel vm) => + vm.WhenAnyValue( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -416,16 +367,14 @@ public static IObservable WithSelector_TwelveProperties(BigViewModel vm) x => x.Prop10, x => x.Prop11, x => x.Prop12, - (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12) => + static (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}_{p10}_{p11}_{p12}"); - /// - /// Thirteen-property observation with a selector using WhenAnyValue. - /// + /// Thirteen-property observation with a selector using WhenAnyValue. /// The view model to observe. /// An observable of the combined string value. - public static IObservable WithSelector_ThirteenProperties(BigViewModel vm) - => vm.WhenAnyValue( + public static IObservable WithSelector_ThirteenProperties(BigViewModel vm) => + vm.WhenAnyValue( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -439,16 +388,14 @@ public static IObservable WithSelector_ThirteenProperties(BigViewModel v x => x.Prop11, x => x.Prop12, x => x.Prop13, - (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13) => + static (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}_{p10}_{p11}_{p12}_{p13}"); - /// - /// Fourteen-property observation with a selector using WhenAnyValue. - /// + /// Fourteen-property observation with a selector using WhenAnyValue. /// The view model to observe. /// An observable of the combined string value. - public static IObservable WithSelector_FourteenProperties(BigViewModel vm) - => vm.WhenAnyValue( + public static IObservable WithSelector_FourteenProperties(BigViewModel vm) => + vm.WhenAnyValue( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -463,16 +410,14 @@ public static IObservable WithSelector_FourteenProperties(BigViewModel v x => x.Prop12, x => x.Prop13, x => x.Prop14, - (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14) => + static (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}_{p10}_{p11}_{p12}_{p13}_{p14}"); - /// - /// Fifteen-property observation with a selector using WhenAnyValue. - /// + /// Fifteen-property observation with a selector using WhenAnyValue. /// The view model to observe. /// An observable of the combined string value. - public static IObservable WithSelector_FifteenProperties(BigViewModel vm) - => vm.WhenAnyValue( + public static IObservable WithSelector_FifteenProperties(BigViewModel vm) => + vm.WhenAnyValue( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -488,16 +433,14 @@ public static IObservable WithSelector_FifteenProperties(BigViewModel vm x => x.Prop13, x => x.Prop14, x => x.Prop15, - (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15) => + static (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}_{p10}_{p11}_{p12}_{p13}_{p14}_{p15}"); - /// - /// Sixteen-property observation with a selector using WhenAnyValue. - /// + /// Sixteen-property observation with a selector using WhenAnyValue. /// The view model to observe. /// An observable of the combined string value. - public static IObservable WithSelector_SixteenProperties(BigViewModel vm) - => vm.WhenAnyValue( + public static IObservable WithSelector_SixteenProperties(BigViewModel vm) => + vm.WhenAnyValue( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -514,16 +457,14 @@ public static IObservable WithSelector_SixteenProperties(BigViewModel vm x => x.Prop14, x => x.Prop15, x => x.Prop16, - (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16) => + static (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}_{p10}_{p11}_{p12}_{p13}_{p14}_{p15}_{p16}"); - /// - /// Deep property chain observation on BigViewModel.Address.City using WhenAnyValue. - /// + /// Deep property chain observation on BigViewModel.Address.City using WhenAnyValue. /// The view model to observe. /// An observable of the nested City property value. - public static IObservable DeepChain_AddressCity(BigViewModel vm) - => vm.WhenAnyValue(x => x.Address.City); + public static IObservable DeepChain_AddressCity(BigViewModel vm) => + vm.WhenAnyValue(x => x.Address.City); /// /// Twelve-property observation using WhenAnyValue on WhenAnyTestFixture (all string properties). @@ -533,8 +474,8 @@ public static IObservable DeepChain_AddressCity(BigViewModel vm) /// An observable of a 12-string tuple. public static IObservable<(string v1, string v2, string v3, string v4, string v5, string v6, string v7, string v8, string v9, - string v10, string v11, string v12)> TwelveProperties_AllStrings(WhenAnyTestFixture fixture) - => fixture.WhenAnyValue( + string v10, string v11, string v12)> TwelveProperties_AllStrings(WhenAnyTestFixture fixture) => + fixture.WhenAnyValue( x => x.Value1, x => x.Value2, x => x.Value3, diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenAnyValueScenarios.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenAnyValueScenarios.cs index 6a2b6c1..68fe844 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenAnyValueScenarios.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenAnyValueScenarios.cs @@ -13,44 +13,34 @@ namespace ReactiveUI.Binding.GeneratedCode.TestModels.Scenarios; /// public static class WhenAnyValueScenarios { - /// - /// Single property observation using WhenAnyValue. - /// + /// Single property observation using WhenAnyValue. /// The fixture to observe. /// An observable of the Value1 property value. - public static IObservable SingleProperty(WhenAnyTestFixture fixture) - => fixture.WhenAnyValue(x => x.Value1); + public static IObservable SingleProperty(WhenAnyTestFixture fixture) => + fixture.WhenAnyValue(x => x.Value1); - /// - /// Two-property observation using WhenAnyValue returning a tuple. - /// + /// Two-property observation using WhenAnyValue returning a tuple. /// The fixture to observe. /// An observable of the property value tuple. - public static IObservable<(string property1, string property2)> TwoProperties(WhenAnyTestFixture fixture) - => fixture.WhenAnyValue(x => x.Value1, x => x.Value2); + public static IObservable<(string property1, string property2)> TwoProperties(WhenAnyTestFixture fixture) => + fixture.WhenAnyValue(x => x.Value1, x => x.Value2); - /// - /// Three-property observation using WhenAnyValue returning a tuple. - /// + /// Three-property observation using WhenAnyValue returning a tuple. /// The fixture to observe. /// An observable of the property value tuple. public static IObservable<(string property1, string property2, string property3)> ThreeProperties( - WhenAnyTestFixture fixture) - => fixture.WhenAnyValue(x => x.Value1, x => x.Value2, x => x.Value3); + WhenAnyTestFixture fixture) => + fixture.WhenAnyValue(x => x.Value1, x => x.Value2, x => x.Value3); - /// - /// Two-property observation with a selector using WhenAnyValue. - /// + /// Two-property observation with a selector using WhenAnyValue. /// The fixture to observe. /// An observable of the combined string value. - public static IObservable WithSelector_TwoProperties(WhenAnyTestFixture fixture) - => fixture.WhenAnyValue(x => x.Value1, x => x.Value2, (v1, v2) => $"{v1}_{v2}"); + public static IObservable WithSelector_TwoProperties(WhenAnyTestFixture fixture) => + fixture.WhenAnyValue(x => x.Value1, x => x.Value2, static (v1, v2) => $"{v1}_{v2}"); - /// - /// Deep property chain observation using WhenAnyValue on BigViewModel.Address.City. - /// + /// Deep property chain observation using WhenAnyValue on BigViewModel.Address.City. /// The view model to observe. /// An observable of the nested City property value. - public static IObservable DeepChain_AddressCity(BigViewModel vm) - => vm.WhenAnyValue(x => x.Address.City); + public static IObservable DeepChain_AddressCity(BigViewModel vm) => + vm.WhenAnyValue(x => x.Address.City); } diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenChangedExtendedScenarios.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenChangedExtendedScenarios.cs index ed87f43..4e0f6d9 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenChangedExtendedScenarios.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenChangedExtendedScenarios.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for full license information. using System; -using System.Diagnostics.CodeAnalysis; using ReactiveUI.Binding.GeneratedCode.TestModels.TestModels; namespace ReactiveUI.Binding.GeneratedCode.TestModels.Scenarios; @@ -12,40 +11,30 @@ namespace ReactiveUI.Binding.GeneratedCode.TestModels.Scenarios; /// Extended scenario methods for WhenChanged that exercise the 5-16 property overloads. /// Each method exercises a specific WhenChanged overload at compile time. /// -[SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "These scenarios intentionally exercise the high-arity (8-16 property) overloads; the selector lambda parameter counts are inherent to the overloads under test.")] public static class WhenChangedExtendedScenarios { - /// - /// Five-property observation returning a tuple. - /// + /// Five-property observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple. public static IObservable<(string property1, int property2, double property3, bool property4, string property5)> - FiveProperties(BigViewModel vm) - => vm.WhenChanged(x => x.Prop1, x => x.Prop2, x => x.Prop3, x => x.Prop4, x => x.Prop5); + FiveProperties(BigViewModel vm) => + vm.WhenChanged(x => x.Prop1, x => x.Prop2, x => x.Prop3, x => x.Prop4, x => x.Prop5); - /// - /// Six-property observation returning a tuple. - /// + /// Six-property observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6)> - SixProperties(BigViewModel vm) - => vm.WhenChanged(x => x.Prop1, x => x.Prop2, x => x.Prop3, x => x.Prop4, x => x.Prop5, x => x.Prop6); + SixProperties(BigViewModel vm) => + vm.WhenChanged(x => x.Prop1, x => x.Prop2, x => x.Prop3, x => x.Prop4, x => x.Prop5, x => x.Prop6); - /// - /// Seven-property observation returning a tuple. - /// + /// Seven-property observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, - double property7)> SevenProperties(BigViewModel vm) - => vm.WhenChanged( + double property7)> SevenProperties(BigViewModel vm) => + vm.WhenChanged( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -54,15 +43,13 @@ public static x => x.Prop6, x => x.Prop7); - /// - /// Eight-property observation returning a tuple. - /// + /// Eight-property observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, - double property7, bool property8)> EightProperties(BigViewModel vm) - => vm.WhenChanged( + double property7, bool property8)> EightProperties(BigViewModel vm) => + vm.WhenChanged( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -72,15 +59,13 @@ public static x => x.Prop7, x => x.Prop8); - /// - /// Nine-property observation returning a tuple. - /// + /// Nine-property observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, - double property7, bool property8, string property9)> NineProperties(BigViewModel vm) - => vm.WhenChanged( + double property7, bool property8, string property9)> NineProperties(BigViewModel vm) => + vm.WhenChanged( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -91,15 +76,13 @@ public static x => x.Prop8, x => x.Prop9); - /// - /// Ten-property observation returning a tuple. - /// + /// Ten-property observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, - double property7, bool property8, string property9, int property10)> TenProperties(BigViewModel vm) - => vm.WhenChanged( + double property7, bool property8, string property9, int property10)> TenProperties(BigViewModel vm) => + vm.WhenChanged( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -111,16 +94,14 @@ public static x => x.Prop9, x => x.Prop10); - /// - /// Eleven-property observation returning a tuple. - /// + /// Eleven-property observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, double property7, bool property8, string property9, int property10, double property11)> ElevenProperties( - BigViewModel vm) - => vm.WhenChanged( + BigViewModel vm) => + vm.WhenChanged( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -133,16 +114,14 @@ public static x => x.Prop10, x => x.Prop11); - /// - /// Twelve-property observation returning a tuple. - /// + /// Twelve-property observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, double property7, bool property8, string property9, int property10, double property11, bool property12)> - TwelveProperties(BigViewModel vm) - => vm.WhenChanged( + TwelveProperties(BigViewModel vm) => + vm.WhenChanged( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -156,15 +135,13 @@ public static x => x.Prop11, x => x.Prop12); - /// - /// Thirteen-property observation returning a tuple. - /// + /// Thirteen-property observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, double property7, bool property8, string property9, int property10, double property11, bool - property12, string property13)> ThirteenProperties(BigViewModel vm) - => vm.WhenChanged( + property12, string property13)> ThirteenProperties(BigViewModel vm) => + vm.WhenChanged( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -179,15 +156,13 @@ public static x => x.Prop12, x => x.Prop13); - /// - /// Fourteen-property observation returning a tuple. - /// + /// Fourteen-property observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, double property7, bool property8, string property9, int property10, double property11, bool - property12, string property13, int property14)> FourteenProperties(BigViewModel vm) - => vm.WhenChanged( + property12, string property13, int property14)> FourteenProperties(BigViewModel vm) => + vm.WhenChanged( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -203,15 +178,13 @@ public static x => x.Prop13, x => x.Prop14); - /// - /// Fifteen-property observation returning a tuple. - /// + /// Fifteen-property observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, double property7, bool property8, string property9, int property10, double property11, bool - property12, string property13, int property14, double property15)> FifteenProperties(BigViewModel vm) - => vm.WhenChanged( + property12, string property13, int property14, double property15)> FifteenProperties(BigViewModel vm) => + vm.WhenChanged( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -228,16 +201,14 @@ public static x => x.Prop14, x => x.Prop15); - /// - /// Sixteen-property observation returning a tuple. - /// + /// Sixteen-property observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, double property7, bool property8, string property9, int property10, double property11, bool property12, string property13, int property14, double property15, bool property16)> SixteenProperties( - BigViewModel vm) - => vm.WhenChanged( + BigViewModel vm) => + vm.WhenChanged( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -255,42 +226,36 @@ public static x => x.Prop15, x => x.Prop16); - /// - /// Five-property observation with a selector function. - /// + /// Five-property observation with a selector function. /// The view model to observe. /// An observable of the combined string value. - public static IObservable WithSelector_FiveProperties(BigViewModel vm) - => vm.WhenChanged( + public static IObservable WithSelector_FiveProperties(BigViewModel vm) => + vm.WhenChanged( x => x.Prop1, x => x.Prop2, x => x.Prop3, x => x.Prop4, x => x.Prop5, - (p1, p2, p3, p4, p5) => $"{p1}_{p2}_{p3}_{p4}_{p5}"); + static (p1, p2, p3, p4, p5) => $"{p1}_{p2}_{p3}_{p4}_{p5}"); - /// - /// Six-property observation with a selector function. - /// + /// Six-property observation with a selector function. /// The view model to observe. /// An observable of the combined string value. - public static IObservable WithSelector_SixProperties(BigViewModel vm) - => vm.WhenChanged( + public static IObservable WithSelector_SixProperties(BigViewModel vm) => + vm.WhenChanged( x => x.Prop1, x => x.Prop2, x => x.Prop3, x => x.Prop4, x => x.Prop5, x => x.Prop6, - (p1, p2, p3, p4, p5, p6) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}"); + static (p1, p2, p3, p4, p5, p6) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}"); - /// - /// Seven-property observation with a selector function. - /// + /// Seven-property observation with a selector function. /// The view model to observe. /// An observable of the combined string value. - public static IObservable WithSelector_SevenProperties(BigViewModel vm) - => vm.WhenChanged( + public static IObservable WithSelector_SevenProperties(BigViewModel vm) => + vm.WhenChanged( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -298,15 +263,13 @@ public static IObservable WithSelector_SevenProperties(BigViewModel vm) x => x.Prop5, x => x.Prop6, x => x.Prop7, - (p1, p2, p3, p4, p5, p6, p7) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}"); + static (p1, p2, p3, p4, p5, p6, p7) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}"); - /// - /// Eight-property observation with a selector function. - /// + /// Eight-property observation with a selector function. /// The view model to observe. /// An observable of the combined string value. - public static IObservable WithSelector_EightProperties(BigViewModel vm) - => vm.WhenChanged( + public static IObservable WithSelector_EightProperties(BigViewModel vm) => + vm.WhenChanged( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -315,15 +278,13 @@ public static IObservable WithSelector_EightProperties(BigViewModel vm) x => x.Prop6, x => x.Prop7, x => x.Prop8, - (p1, p2, p3, p4, p5, p6, p7, p8) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}"); + static (p1, p2, p3, p4, p5, p6, p7, p8) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}"); - /// - /// Nine-property observation with a selector function. - /// + /// Nine-property observation with a selector function. /// The view model to observe. /// An observable of the combined string value. - public static IObservable WithSelector_NineProperties(BigViewModel vm) - => vm.WhenChanged( + public static IObservable WithSelector_NineProperties(BigViewModel vm) => + vm.WhenChanged( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -333,15 +294,13 @@ public static IObservable WithSelector_NineProperties(BigViewModel vm) x => x.Prop7, x => x.Prop8, x => x.Prop9, - (p1, p2, p3, p4, p5, p6, p7, p8, p9) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}"); + static (p1, p2, p3, p4, p5, p6, p7, p8, p9) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}"); - /// - /// Ten-property observation with a selector function. - /// + /// Ten-property observation with a selector function. /// The view model to observe. /// An observable of the combined string value. - public static IObservable WithSelector_TenProperties(BigViewModel vm) - => vm.WhenChanged( + public static IObservable WithSelector_TenProperties(BigViewModel vm) => + vm.WhenChanged( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -352,15 +311,13 @@ public static IObservable WithSelector_TenProperties(BigViewModel vm) x => x.Prop8, x => x.Prop9, x => x.Prop10, - (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}_{p10}"); + static (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}_{p10}"); - /// - /// Eleven-property observation with a selector function. - /// + /// Eleven-property observation with a selector function. /// The view model to observe. /// An observable of the combined string value. - public static IObservable WithSelector_ElevenProperties(BigViewModel vm) - => vm.WhenChanged( + public static IObservable WithSelector_ElevenProperties(BigViewModel vm) => + vm.WhenChanged( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -372,16 +329,14 @@ public static IObservable WithSelector_ElevenProperties(BigViewModel vm) x => x.Prop9, x => x.Prop10, x => x.Prop11, - (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) => + static (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}_{p10}_{p11}"); - /// - /// Twelve-property observation with a selector function. - /// + /// Twelve-property observation with a selector function. /// The view model to observe. /// An observable of the combined string value. - public static IObservable WithSelector_TwelveProperties(BigViewModel vm) - => vm.WhenChanged( + public static IObservable WithSelector_TwelveProperties(BigViewModel vm) => + vm.WhenChanged( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -394,16 +349,14 @@ public static IObservable WithSelector_TwelveProperties(BigViewModel vm) x => x.Prop10, x => x.Prop11, x => x.Prop12, - (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12) => + static (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}_{p10}_{p11}_{p12}"); - /// - /// Thirteen-property observation with a selector function. - /// + /// Thirteen-property observation with a selector function. /// The view model to observe. /// An observable of the combined string value. - public static IObservable WithSelector_ThirteenProperties(BigViewModel vm) - => vm.WhenChanged( + public static IObservable WithSelector_ThirteenProperties(BigViewModel vm) => + vm.WhenChanged( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -417,16 +370,14 @@ public static IObservable WithSelector_ThirteenProperties(BigViewModel v x => x.Prop11, x => x.Prop12, x => x.Prop13, - (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13) => + static (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}_{p10}_{p11}_{p12}_{p13}"); - /// - /// Fourteen-property observation with a selector function. - /// + /// Fourteen-property observation with a selector function. /// The view model to observe. /// An observable of the combined string value. - public static IObservable WithSelector_FourteenProperties(BigViewModel vm) - => vm.WhenChanged( + public static IObservable WithSelector_FourteenProperties(BigViewModel vm) => + vm.WhenChanged( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -441,16 +392,14 @@ public static IObservable WithSelector_FourteenProperties(BigViewModel v x => x.Prop12, x => x.Prop13, x => x.Prop14, - (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14) => + static (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}_{p10}_{p11}_{p12}_{p13}_{p14}"); - /// - /// Fifteen-property observation with a selector function. - /// + /// Fifteen-property observation with a selector function. /// The view model to observe. /// An observable of the combined string value. - public static IObservable WithSelector_FifteenProperties(BigViewModel vm) - => vm.WhenChanged( + public static IObservable WithSelector_FifteenProperties(BigViewModel vm) => + vm.WhenChanged( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -466,16 +415,14 @@ public static IObservable WithSelector_FifteenProperties(BigViewModel vm x => x.Prop13, x => x.Prop14, x => x.Prop15, - (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15) => + static (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}_{p10}_{p11}_{p12}_{p13}_{p14}_{p15}"); - /// - /// Sixteen-property observation with a selector function. - /// + /// Sixteen-property observation with a selector function. /// The view model to observe. /// An observable of the combined string value. - public static IObservable WithSelector_SixteenProperties(BigViewModel vm) - => vm.WhenChanged( + public static IObservable WithSelector_SixteenProperties(BigViewModel vm) => + vm.WhenChanged( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -492,6 +439,6 @@ public static IObservable WithSelector_SixteenProperties(BigViewModel vm x => x.Prop14, x => x.Prop15, x => x.Prop16, - (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16) => + static (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}_{p10}_{p11}_{p12}_{p13}_{p14}_{p15}_{p16}"); } diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenChangedScenarios.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenChangedScenarios.cs index 6c86089..4f8e65b 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenChangedScenarios.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenChangedScenarios.cs @@ -13,62 +13,48 @@ namespace ReactiveUI.Binding.GeneratedCode.TestModels.Scenarios; /// public static class WhenChangedScenarios { - /// - /// Single property observation on TestViewModel.Name. - /// + /// Single property observation on TestViewModel.Name. /// The view model to observe. /// An observable of the Name property value. - public static IObservable SingleProperty_Name(TestViewModel vm) - => vm.WhenChanged(x => x.Name); + public static IObservable SingleProperty_Name(TestViewModel vm) => + vm.WhenChanged(x => x.Name); - /// - /// Single property observation on TestViewModel.Age. - /// + /// Single property observation on TestViewModel.Age. /// The view model to observe. /// An observable of the Age property value. - public static IObservable SingleProperty_Age(TestViewModel vm) - => vm.WhenChanged(x => x.Age); + public static IObservable SingleProperty_Age(TestViewModel vm) => + vm.WhenChanged(x => x.Age); - /// - /// Two-property observation returning a tuple. - /// + /// Two-property observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple. - public static IObservable<(string property1, int property2)> TwoProperties(BigViewModel vm) - => vm.WhenChanged(x => x.Prop1, x => x.Prop2); + public static IObservable<(string property1, int property2)> TwoProperties(BigViewModel vm) => + vm.WhenChanged(x => x.Prop1, x => x.Prop2); - /// - /// Three-property observation returning a tuple. - /// + /// Three-property observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple. - public static IObservable<(string property1, int property2, double property3)> ThreeProperties(BigViewModel vm) - => vm.WhenChanged(x => x.Prop1, x => x.Prop2, x => x.Prop3); + public static IObservable<(string property1, int property2, double property3)> ThreeProperties(BigViewModel vm) => + vm.WhenChanged(x => x.Prop1, x => x.Prop2, x => x.Prop3); - /// - /// Four-property observation returning a tuple. - /// + /// Four-property observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple. public static IObservable<(string property1, int property2, double property3, bool property4)> FourProperties( - BigViewModel vm) - => vm.WhenChanged(x => x.Prop1, x => x.Prop2, x => x.Prop3, x => x.Prop4); + BigViewModel vm) => + vm.WhenChanged(x => x.Prop1, x => x.Prop2, x => x.Prop3, x => x.Prop4); - /// - /// Two-property observation with a selector function. - /// + /// Two-property observation with a selector function. /// The view model to observe. /// An observable of the combined string value. - public static IObservable WithSelector_TwoProperties(BigViewModel vm) - => vm.WhenChanged(x => x.Prop1, x => x.Prop2, (p1, p2) => $"{p1}_{p2}"); + public static IObservable WithSelector_TwoProperties(BigViewModel vm) => + vm.WhenChanged(x => x.Prop1, x => x.Prop2, static (p1, p2) => $"{p1}_{p2}"); - /// - /// Deep property chain observation on BigViewModel.Address.City. - /// + /// Deep property chain observation on BigViewModel.Address.City. /// The view model to observe. /// An observable of the nested City property value. - public static IObservable DeepChain_AddressCity(BigViewModel vm) - => vm.WhenChanged(x => x.Address.City); + public static IObservable DeepChain_AddressCity(BigViewModel vm) => + vm.WhenChanged(x => x.Address.City); /// /// Deep property chain observation on BigViewModel.Address.Street. @@ -76,8 +62,8 @@ public static IObservable DeepChain_AddressCity(BigViewModel vm) /// /// The view model to observe. /// An observable of the nested Street property value. - public static IObservable DeepChain_AddressStreet(BigViewModel vm) - => vm.WhenChanged(x => x.Address.Street); + public static IObservable DeepChain_AddressStreet(BigViewModel vm) => + vm.WhenChanged(x => x.Address.Street); /// /// Deep property chain observation on HostTestFixture.Child!.Name. @@ -85,14 +71,12 @@ public static IObservable DeepChain_AddressStreet(BigViewModel vm) /// /// The host fixture to observe. /// An observable of the nested Name property value. - public static IObservable DeepChain_ChildName(HostTestFixture host) - => host.WhenChanged(x => x.Child!.Name); + public static IObservable DeepChain_ChildName(HostTestFixture host) => + host.WhenChanged(x => x.Child!.Name); - /// - /// Multi-property observation combining a deep chain and a simple property. - /// + /// Multi-property observation combining a deep chain and a simple property. /// The view model to observe. /// An observable of the combined property values. - public static IObservable<(string city, string prop1)> MultiProperty_WithDeepChain(BigViewModel vm) - => vm.WhenChanged(x => x.Address.City, x => x.Prop1); + public static IObservable<(string city, string prop1)> MultiProperty_WithDeepChain(BigViewModel vm) => + vm.WhenChanged(x => x.Address.City, x => x.Prop1); } diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenChangingExtendedScenarios.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenChangingExtendedScenarios.cs index d0b2334..b2056d1 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenChangingExtendedScenarios.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenChangingExtendedScenarios.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for full license information. using System; -using System.Diagnostics.CodeAnalysis; using ReactiveUI.Binding.GeneratedCode.TestModels.TestModels; namespace ReactiveUI.Binding.GeneratedCode.TestModels.Scenarios; @@ -12,40 +11,30 @@ namespace ReactiveUI.Binding.GeneratedCode.TestModels.Scenarios; /// Extended scenario methods for WhenChanging that exercise the 5-16 property overloads. /// Each method exercises a specific WhenChanging overload for before-change observation at compile time. /// -[SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "These scenarios intentionally exercise the high-arity (8-16 property) overloads; the selector lambda parameter counts are inherent to the overloads under test.")] public static class WhenChangingExtendedScenarios { - /// - /// Five-property before-change observation returning a tuple. - /// + /// Five-property before-change observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple before changes. public static IObservable<(string property1, int property2, double property3, bool property4, string property5)> - FiveProperties(BigViewModel vm) - => vm.WhenChanging(x => x.Prop1, x => x.Prop2, x => x.Prop3, x => x.Prop4, x => x.Prop5); + FiveProperties(BigViewModel vm) => + vm.WhenChanging(x => x.Prop1, x => x.Prop2, x => x.Prop3, x => x.Prop4, x => x.Prop5); - /// - /// Six-property before-change observation returning a tuple. - /// + /// Six-property before-change observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple before changes. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6)> - SixProperties(BigViewModel vm) - => vm.WhenChanging(x => x.Prop1, x => x.Prop2, x => x.Prop3, x => x.Prop4, x => x.Prop5, x => x.Prop6); + SixProperties(BigViewModel vm) => + vm.WhenChanging(x => x.Prop1, x => x.Prop2, x => x.Prop3, x => x.Prop4, x => x.Prop5, x => x.Prop6); - /// - /// Seven-property before-change observation returning a tuple. - /// + /// Seven-property before-change observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple before changes. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, - double property7)> SevenProperties(BigViewModel vm) - => vm.WhenChanging( + double property7)> SevenProperties(BigViewModel vm) => + vm.WhenChanging( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -54,15 +43,13 @@ public static x => x.Prop6, x => x.Prop7); - /// - /// Eight-property before-change observation returning a tuple. - /// + /// Eight-property before-change observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple before changes. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, - double property7, bool property8)> EightProperties(BigViewModel vm) - => vm.WhenChanging( + double property7, bool property8)> EightProperties(BigViewModel vm) => + vm.WhenChanging( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -72,15 +59,13 @@ public static x => x.Prop7, x => x.Prop8); - /// - /// Nine-property before-change observation returning a tuple. - /// + /// Nine-property before-change observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple before changes. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, - double property7, bool property8, string property9)> NineProperties(BigViewModel vm) - => vm.WhenChanging( + double property7, bool property8, string property9)> NineProperties(BigViewModel vm) => + vm.WhenChanging( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -91,15 +76,13 @@ public static x => x.Prop8, x => x.Prop9); - /// - /// Ten-property before-change observation returning a tuple. - /// + /// Ten-property before-change observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple before changes. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, - double property7, bool property8, string property9, int property10)> TenProperties(BigViewModel vm) - => vm.WhenChanging( + double property7, bool property8, string property9, int property10)> TenProperties(BigViewModel vm) => + vm.WhenChanging( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -111,16 +94,14 @@ public static x => x.Prop9, x => x.Prop10); - /// - /// Eleven-property before-change observation returning a tuple. - /// + /// Eleven-property before-change observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple before changes. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, double property7, bool property8, string property9, int property10, double property11)> ElevenProperties( - BigViewModel vm) - => vm.WhenChanging( + BigViewModel vm) => + vm.WhenChanging( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -133,16 +114,14 @@ public static x => x.Prop10, x => x.Prop11); - /// - /// Twelve-property before-change observation returning a tuple. - /// + /// Twelve-property before-change observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple before changes. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, double property7, bool property8, string property9, int property10, double property11, bool property12)> - TwelveProperties(BigViewModel vm) - => vm.WhenChanging( + TwelveProperties(BigViewModel vm) => + vm.WhenChanging( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -156,15 +135,13 @@ public static x => x.Prop11, x => x.Prop12); - /// - /// Thirteen-property before-change observation returning a tuple. - /// + /// Thirteen-property before-change observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple before changes. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, double property7, bool property8, string property9, int property10, double property11, bool - property12, string property13)> ThirteenProperties(BigViewModel vm) - => vm.WhenChanging( + property12, string property13)> ThirteenProperties(BigViewModel vm) => + vm.WhenChanging( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -179,15 +156,13 @@ public static x => x.Prop12, x => x.Prop13); - /// - /// Fourteen-property before-change observation returning a tuple. - /// + /// Fourteen-property before-change observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple before changes. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, double property7, bool property8, string property9, int property10, double property11, bool - property12, string property13, int property14)> FourteenProperties(BigViewModel vm) - => vm.WhenChanging( + property12, string property13, int property14)> FourteenProperties(BigViewModel vm) => + vm.WhenChanging( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -203,15 +178,13 @@ public static x => x.Prop13, x => x.Prop14); - /// - /// Fifteen-property before-change observation returning a tuple. - /// + /// Fifteen-property before-change observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple before changes. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, double property7, bool property8, string property9, int property10, double property11, bool - property12, string property13, int property14, double property15)> FifteenProperties(BigViewModel vm) - => vm.WhenChanging( + property12, string property13, int property14, double property15)> FifteenProperties(BigViewModel vm) => + vm.WhenChanging( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -228,16 +201,14 @@ public static x => x.Prop14, x => x.Prop15); - /// - /// Sixteen-property before-change observation returning a tuple. - /// + /// Sixteen-property before-change observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple before changes. public static IObservable<(string property1, int property2, double property3, bool property4, string property5, int property6, double property7, bool property8, string property9, int property10, double property11, bool property12, string property13, int property14, double property15, bool property16)> SixteenProperties( - BigViewModel vm) - => vm.WhenChanging( + BigViewModel vm) => + vm.WhenChanging( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -255,42 +226,36 @@ public static x => x.Prop15, x => x.Prop16); - /// - /// Five-property before-change observation with a selector function. - /// + /// Five-property before-change observation with a selector function. /// The view model to observe. /// An observable of the combined string value before changes. - public static IObservable WithSelector_FiveProperties(BigViewModel vm) - => vm.WhenChanging( + public static IObservable WithSelector_FiveProperties(BigViewModel vm) => + vm.WhenChanging( x => x.Prop1, x => x.Prop2, x => x.Prop3, x => x.Prop4, x => x.Prop5, - (p1, p2, p3, p4, p5) => $"{p1}_{p2}_{p3}_{p4}_{p5}"); + static (p1, p2, p3, p4, p5) => $"{p1}_{p2}_{p3}_{p4}_{p5}"); - /// - /// Six-property before-change observation with a selector function. - /// + /// Six-property before-change observation with a selector function. /// The view model to observe. /// An observable of the combined string value before changes. - public static IObservable WithSelector_SixProperties(BigViewModel vm) - => vm.WhenChanging( + public static IObservable WithSelector_SixProperties(BigViewModel vm) => + vm.WhenChanging( x => x.Prop1, x => x.Prop2, x => x.Prop3, x => x.Prop4, x => x.Prop5, x => x.Prop6, - (p1, p2, p3, p4, p5, p6) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}"); + static (p1, p2, p3, p4, p5, p6) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}"); - /// - /// Seven-property before-change observation with a selector function. - /// + /// Seven-property before-change observation with a selector function. /// The view model to observe. /// An observable of the combined string value before changes. - public static IObservable WithSelector_SevenProperties(BigViewModel vm) - => vm.WhenChanging( + public static IObservable WithSelector_SevenProperties(BigViewModel vm) => + vm.WhenChanging( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -298,15 +263,13 @@ public static IObservable WithSelector_SevenProperties(BigViewModel vm) x => x.Prop5, x => x.Prop6, x => x.Prop7, - (p1, p2, p3, p4, p5, p6, p7) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}"); + static (p1, p2, p3, p4, p5, p6, p7) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}"); - /// - /// Eight-property before-change observation with a selector function. - /// + /// Eight-property before-change observation with a selector function. /// The view model to observe. /// An observable of the combined string value before changes. - public static IObservable WithSelector_EightProperties(BigViewModel vm) - => vm.WhenChanging( + public static IObservable WithSelector_EightProperties(BigViewModel vm) => + vm.WhenChanging( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -315,15 +278,13 @@ public static IObservable WithSelector_EightProperties(BigViewModel vm) x => x.Prop6, x => x.Prop7, x => x.Prop8, - (p1, p2, p3, p4, p5, p6, p7, p8) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}"); + static (p1, p2, p3, p4, p5, p6, p7, p8) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}"); - /// - /// Nine-property before-change observation with a selector function. - /// + /// Nine-property before-change observation with a selector function. /// The view model to observe. /// An observable of the combined string value before changes. - public static IObservable WithSelector_NineProperties(BigViewModel vm) - => vm.WhenChanging( + public static IObservable WithSelector_NineProperties(BigViewModel vm) => + vm.WhenChanging( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -333,15 +294,13 @@ public static IObservable WithSelector_NineProperties(BigViewModel vm) x => x.Prop7, x => x.Prop8, x => x.Prop9, - (p1, p2, p3, p4, p5, p6, p7, p8, p9) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}"); + static (p1, p2, p3, p4, p5, p6, p7, p8, p9) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}"); - /// - /// Ten-property before-change observation with a selector function. - /// + /// Ten-property before-change observation with a selector function. /// The view model to observe. /// An observable of the combined string value before changes. - public static IObservable WithSelector_TenProperties(BigViewModel vm) - => vm.WhenChanging( + public static IObservable WithSelector_TenProperties(BigViewModel vm) => + vm.WhenChanging( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -352,15 +311,13 @@ public static IObservable WithSelector_TenProperties(BigViewModel vm) x => x.Prop8, x => x.Prop9, x => x.Prop10, - (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}_{p10}"); + static (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}_{p10}"); - /// - /// Eleven-property before-change observation with a selector function. - /// + /// Eleven-property before-change observation with a selector function. /// The view model to observe. /// An observable of the combined string value before changes. - public static IObservable WithSelector_ElevenProperties(BigViewModel vm) - => vm.WhenChanging( + public static IObservable WithSelector_ElevenProperties(BigViewModel vm) => + vm.WhenChanging( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -372,16 +329,14 @@ public static IObservable WithSelector_ElevenProperties(BigViewModel vm) x => x.Prop9, x => x.Prop10, x => x.Prop11, - (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) => + static (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}_{p10}_{p11}"); - /// - /// Twelve-property before-change observation with a selector function. - /// + /// Twelve-property before-change observation with a selector function. /// The view model to observe. /// An observable of the combined string value before changes. - public static IObservable WithSelector_TwelveProperties(BigViewModel vm) - => vm.WhenChanging( + public static IObservable WithSelector_TwelveProperties(BigViewModel vm) => + vm.WhenChanging( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -394,16 +349,14 @@ public static IObservable WithSelector_TwelveProperties(BigViewModel vm) x => x.Prop10, x => x.Prop11, x => x.Prop12, - (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12) => + static (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}_{p10}_{p11}_{p12}"); - /// - /// Thirteen-property before-change observation with a selector function. - /// + /// Thirteen-property before-change observation with a selector function. /// The view model to observe. /// An observable of the combined string value before changes. - public static IObservable WithSelector_ThirteenProperties(BigViewModel vm) - => vm.WhenChanging( + public static IObservable WithSelector_ThirteenProperties(BigViewModel vm) => + vm.WhenChanging( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -417,16 +370,14 @@ public static IObservable WithSelector_ThirteenProperties(BigViewModel v x => x.Prop11, x => x.Prop12, x => x.Prop13, - (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13) => + static (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}_{p10}_{p11}_{p12}_{p13}"); - /// - /// Fourteen-property before-change observation with a selector function. - /// + /// Fourteen-property before-change observation with a selector function. /// The view model to observe. /// An observable of the combined string value before changes. - public static IObservable WithSelector_FourteenProperties(BigViewModel vm) - => vm.WhenChanging( + public static IObservable WithSelector_FourteenProperties(BigViewModel vm) => + vm.WhenChanging( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -441,16 +392,14 @@ public static IObservable WithSelector_FourteenProperties(BigViewModel v x => x.Prop12, x => x.Prop13, x => x.Prop14, - (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14) => + static (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}_{p10}_{p11}_{p12}_{p13}_{p14}"); - /// - /// Fifteen-property before-change observation with a selector function. - /// + /// Fifteen-property before-change observation with a selector function. /// The view model to observe. /// An observable of the combined string value before changes. - public static IObservable WithSelector_FifteenProperties(BigViewModel vm) - => vm.WhenChanging( + public static IObservable WithSelector_FifteenProperties(BigViewModel vm) => + vm.WhenChanging( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -466,16 +415,14 @@ public static IObservable WithSelector_FifteenProperties(BigViewModel vm x => x.Prop13, x => x.Prop14, x => x.Prop15, - (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15) => + static (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}_{p10}_{p11}_{p12}_{p13}_{p14}_{p15}"); - /// - /// Sixteen-property before-change observation with a selector function. - /// + /// Sixteen-property before-change observation with a selector function. /// The view model to observe. /// An observable of the combined string value before changes. - public static IObservable WithSelector_SixteenProperties(BigViewModel vm) - => vm.WhenChanging( + public static IObservable WithSelector_SixteenProperties(BigViewModel vm) => + vm.WhenChanging( x => x.Prop1, x => x.Prop2, x => x.Prop3, @@ -492,14 +439,12 @@ public static IObservable WithSelector_SixteenProperties(BigViewModel vm x => x.Prop14, x => x.Prop15, x => x.Prop16, - (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16) => + static (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16) => $"{p1}_{p2}_{p3}_{p4}_{p5}_{p6}_{p7}_{p8}_{p9}_{p10}_{p11}_{p12}_{p13}_{p14}_{p15}_{p16}"); - /// - /// Deep property chain before-change observation on BigViewModel.Address.City. - /// + /// Deep property chain before-change observation on BigViewModel.Address.City. /// The view model to observe. /// An observable of the nested City property value before changes. - public static IObservable DeepChain_AddressCity(BigViewModel vm) - => vm.WhenChanging(x => x.Address.City); + public static IObservable DeepChain_AddressCity(BigViewModel vm) => + vm.WhenChanging(x => x.Address.City); } diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenChangingScenarios.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenChangingScenarios.cs index 9223cd3..89ae231 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenChangingScenarios.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/Scenarios/WhenChangingScenarios.cs @@ -13,52 +13,40 @@ namespace ReactiveUI.Binding.GeneratedCode.TestModels.Scenarios; /// public static class WhenChangingScenarios { - /// - /// Single property before-change observation on TestViewModel.Name. - /// + /// Single property before-change observation on TestViewModel.Name. /// The view model to observe. /// An observable of the Name property value before changes. - public static IObservable SingleProperty_Name(TestViewModel vm) - => vm.WhenChanging(x => x.Name); + public static IObservable SingleProperty_Name(TestViewModel vm) => + vm.WhenChanging(x => x.Name); - /// - /// Single property before-change observation on BigViewModel.Prop1. - /// + /// Single property before-change observation on BigViewModel.Prop1. /// The view model to observe. /// An observable of the Prop1 property value before changes. - public static IObservable SingleProperty_Prop1(BigViewModel vm) - => vm.WhenChanging(x => x.Prop1); + public static IObservable SingleProperty_Prop1(BigViewModel vm) => + vm.WhenChanging(x => x.Prop1); - /// - /// Two-property before-change observation returning a tuple. - /// + /// Two-property before-change observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple before changes. - public static IObservable<(string property1, int property2)> TwoProperties(BigViewModel vm) - => vm.WhenChanging(x => x.Prop1, x => x.Prop2); + public static IObservable<(string property1, int property2)> TwoProperties(BigViewModel vm) => + vm.WhenChanging(x => x.Prop1, x => x.Prop2); - /// - /// Three-property before-change observation returning a tuple. - /// + /// Three-property before-change observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple before changes. - public static IObservable<(string property1, int property2, double property3)> ThreeProperties(BigViewModel vm) - => vm.WhenChanging(x => x.Prop1, x => x.Prop2, x => x.Prop3); + public static IObservable<(string property1, int property2, double property3)> ThreeProperties(BigViewModel vm) => + vm.WhenChanging(x => x.Prop1, x => x.Prop2, x => x.Prop3); - /// - /// Four-property before-change observation returning a tuple. - /// + /// Four-property before-change observation returning a tuple. /// The view model to observe. /// An observable of the property value tuple before changes. public static IObservable<(string property1, int property2, double property3, bool property4)> FourProperties( - BigViewModel vm) - => vm.WhenChanging(x => x.Prop1, x => x.Prop2, x => x.Prop3, x => x.Prop4); + BigViewModel vm) => + vm.WhenChanging(x => x.Prop1, x => x.Prop2, x => x.Prop3, x => x.Prop4); - /// - /// Deep property chain before-change observation on BigViewModel.Address.City. - /// + /// Deep property chain before-change observation on BigViewModel.Address.City. /// The view model to observe. /// An observable of the nested City property value before changes. - public static IObservable DeepChain_AddressCity(BigViewModel vm) - => vm.WhenChanging(x => x.Address.City); + public static IObservable DeepChain_AddressCity(BigViewModel vm) => + vm.WhenChanging(x => x.Address.City); } diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/Address.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/Address.cs index 98ee683..39d5e57 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/Address.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/Address.cs @@ -6,87 +6,63 @@ namespace ReactiveUI.Binding.GeneratedCode.TestModels.TestModels; -/// -/// An address model for testing deep property chains. -/// Implements both INotifyPropertyChanged and INotifyPropertyChanging. -/// +/// An address model for testing deep property chains. Implements both INotifyPropertyChanged and INotifyPropertyChanging. public class Address : INotifyPropertyChanged, INotifyPropertyChanging { - /// - /// The backer for Street. - /// - private string _street = string.Empty; - - /// - /// The backer for City. - /// - private string _city = string.Empty; - - /// - /// The backer for ZipCode. - /// - private string _zipCode = string.Empty; - /// public event PropertyChangedEventHandler? PropertyChanged; /// public event PropertyChangingEventHandler? PropertyChanging; - /// - /// Gets or sets the street. - /// + /// Gets or sets the street. public string Street { - get => _street; + get => field; set { - if (_street == value) + if (field == value) { return; } PropertyChanging?.Invoke(this, new(nameof(Street))); - _street = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Street))); } - } + } = string.Empty; - /// - /// Gets or sets the city. - /// + /// Gets or sets the city. public string City { - get => _city; + get => field; set { - if (_city == value) + if (field == value) { return; } PropertyChanging?.Invoke(this, new(nameof(City))); - _city = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(City))); } - } + } = string.Empty; - /// - /// Gets or sets the zip code. - /// + /// Gets or sets the zip code. public string ZipCode { - get => _zipCode; + get => field; set { - if (_zipCode == value) + if (field == value) { return; } PropertyChanging?.Invoke(this, new(nameof(ZipCode))); - _zipCode = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(ZipCode))); } - } + } = string.Empty; } diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/BigView.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/BigView.cs index fdb4102..ec00c24 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/BigView.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/BigView.cs @@ -13,373 +13,261 @@ namespace ReactiveUI.Binding.GeneratedCode.TestModels.TestModels; /// public class BigView : INotifyPropertyChanged { - /// - /// The backer for ViewProp1. - /// - private string _viewProp1 = string.Empty; - - /// - /// The backer for ViewProp2. - /// - private int _viewProp2; - - /// - /// The backer for ViewProp3. - /// - private double _viewProp3; - - /// - /// The backer for ViewProp4. - /// - private bool _viewProp4; - - /// - /// The backer for ViewProp5. - /// - private string _viewProp5 = string.Empty; - - /// - /// The backer for ViewProp6. - /// - private int _viewProp6; - - /// - /// The backer for ViewProp7. - /// - private double _viewProp7; - - /// - /// The backer for ViewProp8. - /// - private bool _viewProp8; - - /// - /// The backer for ViewProp9. - /// - private string _viewProp9 = string.Empty; - - /// - /// The backer for ViewProp10. - /// - private int _viewProp10; - - /// - /// The backer for ViewProp11. - /// - private double _viewProp11; - - /// - /// The backer for ViewProp12. - /// - private bool _viewProp12; - - /// - /// The backer for ViewProp13. - /// - private string _viewProp13 = string.Empty; - - /// - /// The backer for ViewProp14. - /// - private int _viewProp14; - - /// - /// The backer for ViewProp15. - /// - private double _viewProp15; - - /// - /// The backer for ViewProp16. - /// - private bool _viewProp16; - /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets view prop1 (string). - /// + /// Gets or sets view prop1 (string). public string ViewProp1 { - get => _viewProp1; + get => field; set { - if (_viewProp1 == value) + if (field == value) { return; } - _viewProp1 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(ViewProp1))); } - } + } = string.Empty; - /// - /// Gets or sets view prop2 (int). - /// + /// Gets or sets view prop2 (int). public int ViewProp2 { - get => _viewProp2; + get => field; set { - if (_viewProp2 == value) + if (field == value) { return; } - _viewProp2 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(ViewProp2))); } } - /// - /// Gets or sets view prop3 (double). - /// + /// Gets or sets view prop3 (double). public double ViewProp3 { - get => _viewProp3; + get => field; set { - if (Math.Abs(_viewProp3 - value) <= double.Epsilon) + if (Math.Abs(field - value) <= double.Epsilon) { return; } - _viewProp3 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(ViewProp3))); } } - /// - /// Gets or sets a value indicating whether view prop4 is true. - /// + /// Gets or sets a value indicating whether view prop4 is true. public bool ViewProp4 { - get => _viewProp4; + get => field; set { - if (_viewProp4 == value) + if (field == value) { return; } - _viewProp4 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(ViewProp4))); } } - /// - /// Gets or sets view prop5 (string). - /// + /// Gets or sets view prop5 (string). public string ViewProp5 { - get => _viewProp5; + get => field; set { - if (_viewProp5 == value) + if (field == value) { return; } - _viewProp5 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(ViewProp5))); } - } + } = string.Empty; - /// - /// Gets or sets view prop6 (int). - /// + /// Gets or sets view prop6 (int). public int ViewProp6 { - get => _viewProp6; + get => field; set { - if (_viewProp6 == value) + if (field == value) { return; } - _viewProp6 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(ViewProp6))); } } - /// - /// Gets or sets view prop7 (double). - /// + /// Gets or sets view prop7 (double). public double ViewProp7 { - get => _viewProp7; + get => field; set { - if (Math.Abs(_viewProp7 - value) <= double.Epsilon) + if (Math.Abs(field - value) <= double.Epsilon) { return; } - _viewProp7 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(ViewProp7))); } } - /// - /// Gets or sets a value indicating whether view prop8 is true. - /// + /// Gets or sets a value indicating whether view prop8 is true. public bool ViewProp8 { - get => _viewProp8; + get => field; set { - if (_viewProp8 == value) + if (field == value) { return; } - _viewProp8 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(ViewProp8))); } } - /// - /// Gets or sets view prop9 (string). - /// + /// Gets or sets view prop9 (string). public string ViewProp9 { - get => _viewProp9; + get => field; set { - if (_viewProp9 == value) + if (field == value) { return; } - _viewProp9 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(ViewProp9))); } - } + } = string.Empty; - /// - /// Gets or sets view prop10 (int). - /// + /// Gets or sets view prop10 (int). public int ViewProp10 { - get => _viewProp10; + get => field; set { - if (_viewProp10 == value) + if (field == value) { return; } - _viewProp10 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(ViewProp10))); } } - /// - /// Gets or sets view prop11 (double). - /// + /// Gets or sets view prop11 (double). public double ViewProp11 { - get => _viewProp11; + get => field; set { - if (Math.Abs(_viewProp11 - value) <= double.Epsilon) + if (Math.Abs(field - value) <= double.Epsilon) { return; } - _viewProp11 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(ViewProp11))); } } - /// - /// Gets or sets a value indicating whether view prop12 is true. - /// + /// Gets or sets a value indicating whether view prop12 is true. public bool ViewProp12 { - get => _viewProp12; + get => field; set { - if (_viewProp12 == value) + if (field == value) { return; } - _viewProp12 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(ViewProp12))); } } - /// - /// Gets or sets view prop13 (string). - /// + /// Gets or sets view prop13 (string). public string ViewProp13 { - get => _viewProp13; + get => field; set { - if (_viewProp13 == value) + if (field == value) { return; } - _viewProp13 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(ViewProp13))); } - } + } = string.Empty; - /// - /// Gets or sets view prop14 (int). - /// + /// Gets or sets view prop14 (int). public int ViewProp14 { - get => _viewProp14; + get => field; set { - if (_viewProp14 == value) + if (field == value) { return; } - _viewProp14 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(ViewProp14))); } } - /// - /// Gets or sets view prop15 (double). - /// + /// Gets or sets view prop15 (double). public double ViewProp15 { - get => _viewProp15; + get => field; set { - if (Math.Abs(_viewProp15 - value) <= double.Epsilon) + if (Math.Abs(field - value) <= double.Epsilon) { return; } - _viewProp15 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(ViewProp15))); } } - /// - /// Gets or sets a value indicating whether view prop16 is true. - /// + /// Gets or sets a value indicating whether view prop16 is true. public bool ViewProp16 { - get => _viewProp16; + get => field; set { - if (_viewProp16 == value) + if (field == value) { return; } - _viewProp16 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(ViewProp16))); } } diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/BigViewModel.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/BigViewModel.cs index 24eb3d8..77dfcbb 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/BigViewModel.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/BigViewModel.cs @@ -14,90 +14,29 @@ namespace ReactiveUI.Binding.GeneratedCode.TestModels.TestModels; /// public class BigViewModel : INotifyPropertyChanged, INotifyPropertyChanging { - /// - /// The backer for Prop1. - /// - private string _prop1 = string.Empty; + /// Seed for ; each seed is the property's own ordinal so no two values collide. + private const int Prop2Seed = 2; - /// - /// The backer for Prop2. - /// - private int _prop2; + /// Seed for . + private const double Prop3Seed = 3.0; - /// - /// The backer for Prop3. - /// - private double _prop3; - - /// - /// The backer for Prop4. - /// - private bool _prop4; - - /// - /// The backer for Prop5. - /// - private string _prop5 = string.Empty; + /// Seed for . + private const int Prop6Seed = 6; - /// - /// The backer for Prop6. - /// - private int _prop6; + /// Seed for . + private const double Prop7Seed = 7.0; - /// - /// The backer for Prop7. - /// - private double _prop7; + /// Seed for . + private const int Prop10Seed = 10; - /// - /// The backer for Prop8. - /// - private bool _prop8; + /// Seed for . + private const double Prop11Seed = 11.0; - /// - /// The backer for Prop9. - /// - private string _prop9 = string.Empty; + /// Seed for . + private const int Prop14Seed = 14; - /// - /// The backer for Prop10. - /// - private int _prop10; - - /// - /// The backer for Prop11. - /// - private double _prop11; - - /// - /// The backer for Prop12. - /// - private bool _prop12; - - /// - /// The backer for Prop13. - /// - private string _prop13 = string.Empty; - - /// - /// The backer for Prop14. - /// - private int _prop14; - - /// - /// The backer for Prop15. - /// - private double _prop15; - - /// - /// The backer for Prop16. - /// - private bool _prop16; - - /// - /// The backer for Address. - /// - private Address _address = new(); + /// Seed for . + private const double Prop15Seed = 15.0; /// public event PropertyChangedEventHandler? PropertyChanged; @@ -105,326 +44,317 @@ public class BigViewModel : INotifyPropertyChanged, INotifyPropertyChanging /// public event PropertyChangingEventHandler? PropertyChanging; - /// - /// Gets or sets prop1 (string). - /// + /// Gets or sets prop1 (string). public string Prop1 { - get => _prop1; + get => field; set { - if (_prop1 == value) + if (field == value) { return; } PropertyChanging?.Invoke(this, new(nameof(Prop1))); - _prop1 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Prop1))); } - } + } = string.Empty; - /// - /// Gets or sets prop2 (int). - /// + /// Gets or sets prop2 (int). public int Prop2 { - get => _prop2; + get => field; set { - if (_prop2 == value) + if (field == value) { return; } PropertyChanging?.Invoke(this, new(nameof(Prop2))); - _prop2 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Prop2))); } } - /// - /// Gets or sets prop3 (double). - /// + /// Gets or sets prop3 (double). public double Prop3 { - get => _prop3; + get => field; set { - if (Math.Abs(_prop3 - value) <= double.Epsilon) + if (Math.Abs(field - value) <= double.Epsilon) { return; } PropertyChanging?.Invoke(this, new(nameof(Prop3))); - _prop3 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Prop3))); } } - /// - /// Gets or sets a value indicating whether prop4 is true. - /// + /// Gets or sets a value indicating whether prop4 is true. public bool Prop4 { - get => _prop4; + get => field; set { - if (_prop4 == value) + if (field == value) { return; } PropertyChanging?.Invoke(this, new(nameof(Prop4))); - _prop4 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Prop4))); } } - /// - /// Gets or sets prop5 (string). - /// + /// Gets or sets prop5 (string). public string Prop5 { - get => _prop5; + get => field; set { - if (_prop5 == value) + if (field == value) { return; } PropertyChanging?.Invoke(this, new(nameof(Prop5))); - _prop5 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Prop5))); } - } + } = string.Empty; - /// - /// Gets or sets prop6 (int). - /// + /// Gets or sets prop6 (int). public int Prop6 { - get => _prop6; + get => field; set { - if (_prop6 == value) + if (field == value) { return; } PropertyChanging?.Invoke(this, new(nameof(Prop6))); - _prop6 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Prop6))); } } - /// - /// Gets or sets prop7 (double). - /// + /// Gets or sets prop7 (double). public double Prop7 { - get => _prop7; + get => field; set { - if (Math.Abs(_prop7 - value) <= double.Epsilon) + if (Math.Abs(field - value) <= double.Epsilon) { return; } PropertyChanging?.Invoke(this, new(nameof(Prop7))); - _prop7 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Prop7))); } } - /// - /// Gets or sets a value indicating whether prop8 is true. - /// + /// Gets or sets a value indicating whether prop8 is true. public bool Prop8 { - get => _prop8; + get => field; set { - if (_prop8 == value) + if (field == value) { return; } PropertyChanging?.Invoke(this, new(nameof(Prop8))); - _prop8 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Prop8))); } } - /// - /// Gets or sets prop9 (string). - /// + /// Gets or sets prop9 (string). public string Prop9 { - get => _prop9; + get => field; set { - if (_prop9 == value) + if (field == value) { return; } PropertyChanging?.Invoke(this, new(nameof(Prop9))); - _prop9 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Prop9))); } - } + } = string.Empty; - /// - /// Gets or sets prop10 (int). - /// + /// Gets or sets prop10 (int). public int Prop10 { - get => _prop10; + get => field; set { - if (_prop10 == value) + if (field == value) { return; } PropertyChanging?.Invoke(this, new(nameof(Prop10))); - _prop10 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Prop10))); } } - /// - /// Gets or sets prop11 (double). - /// + /// Gets or sets prop11 (double). public double Prop11 { - get => _prop11; + get => field; set { - if (Math.Abs(_prop11 - value) <= double.Epsilon) + if (Math.Abs(field - value) <= double.Epsilon) { return; } PropertyChanging?.Invoke(this, new(nameof(Prop11))); - _prop11 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Prop11))); } } - /// - /// Gets or sets a value indicating whether prop12 is true. - /// + /// Gets or sets a value indicating whether prop12 is true. public bool Prop12 { - get => _prop12; + get => field; set { - if (_prop12 == value) + if (field == value) { return; } PropertyChanging?.Invoke(this, new(nameof(Prop12))); - _prop12 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Prop12))); } } - /// - /// Gets or sets prop13 (string). - /// + /// Gets or sets prop13 (string). public string Prop13 { - get => _prop13; + get => field; set { - if (_prop13 == value) + if (field == value) { return; } PropertyChanging?.Invoke(this, new(nameof(Prop13))); - _prop13 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Prop13))); } - } + } = string.Empty; - /// - /// Gets or sets prop14 (int). - /// + /// Gets or sets prop14 (int). public int Prop14 { - get => _prop14; + get => field; set { - if (_prop14 == value) + if (field == value) { return; } PropertyChanging?.Invoke(this, new(nameof(Prop14))); - _prop14 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Prop14))); } } - /// - /// Gets or sets prop15 (double). - /// + /// Gets or sets prop15 (double). public double Prop15 { - get => _prop15; + get => field; set { - if (Math.Abs(_prop15 - value) <= double.Epsilon) + if (Math.Abs(field - value) <= double.Epsilon) { return; } PropertyChanging?.Invoke(this, new(nameof(Prop15))); - _prop15 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Prop15))); } } - /// - /// Gets or sets a value indicating whether prop16 is true. - /// + /// Gets or sets a value indicating whether prop16 is true. public bool Prop16 { - get => _prop16; + get => field; set { - if (_prop16 == value) + if (field == value) { return; } PropertyChanging?.Invoke(this, new(nameof(Prop16))); - _prop16 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Prop16))); } } - /// - /// Gets or sets the address for deep property chain testing. - /// + /// Gets or sets the address for deep property chain testing. public Address Address { - get => _address; + get => field; set { - if (_address == value) + if (field == value) { return; } PropertyChanging?.Invoke(this, new(nameof(Address))); - _address = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Address))); } - } + } = new(); + + /// + /// Creates an instance with every property set to a distinct non-default value, so a test observing + /// any subset of the sixteen properties starts from a fully populated model. + /// + /// A populated view model. + public static BigViewModel CreatePopulated() => new() + { + Prop1 = "a", + Prop2 = Prop2Seed, + Prop3 = Prop3Seed, + Prop4 = true, + Prop5 = "e", + Prop6 = Prop6Seed, + Prop7 = Prop7Seed, + Prop8 = false, + Prop9 = "i", + Prop10 = Prop10Seed, + Prop11 = Prop11Seed, + Prop12 = true, + Prop13 = "m", + Prop14 = Prop14Seed, + Prop15 = Prop15Seed, + Prop16 = false, + }; } diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/HostTestFixture.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/HostTestFixture.cs index a8f01dd..15c0090 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/HostTestFixture.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/HostTestFixture.cs @@ -12,32 +12,25 @@ namespace ReactiveUI.Binding.GeneratedCode.TestModels.TestModels; /// public class HostTestFixture : INotifyPropertyChanged, INotifyPropertyChanging { - /// - /// The backer for Child. - /// - private TestViewModel? _child; - /// public event PropertyChangedEventHandler? PropertyChanged; /// public event PropertyChangingEventHandler? PropertyChanging; - /// - /// Gets or sets the child view model for deep chain testing. - /// + /// Gets or sets the child view model for deep chain testing. public TestViewModel? Child { - get => _child; + get => field; set { - if (_child == value) + if (field == value) { return; } PropertyChanging?.Invoke(this, new(nameof(Child))); - _child = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Child))); } } diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/ObservablePropertyViewModel.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/ObservablePropertyViewModel.cs index 078ef1d..088ecd1 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/ObservablePropertyViewModel.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/ObservablePropertyViewModel.cs @@ -13,47 +13,37 @@ namespace ReactiveUI.Binding.GeneratedCode.TestModels.TestModels; /// public class ObservablePropertyViewModel : INotifyPropertyChanged { - /// The backing field for . - private IObservable? _myCommand; - - /// The backing field for . - private IObservable? _otherCommand; - /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the command observable. - /// + /// Gets or sets the command observable. public IObservable? MyCommand { - get => _myCommand; + get => field; set { - if (_myCommand == value) + if (field == value) { return; } - _myCommand = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(MyCommand))); } } - /// - /// Gets or sets another command observable. - /// + /// Gets or sets another command observable. public IObservable? OtherCommand { - get => _otherCommand; + get => field; set { - if (_otherCommand == value) + if (field == value) { return; } - _otherCommand = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(OtherCommand))); } } diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/TestView.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/TestView.cs index f231e9f..ac09f46 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/TestView.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/TestView.cs @@ -12,54 +12,40 @@ namespace ReactiveUI.Binding.GeneratedCode.TestModels.TestModels; /// public class TestView : INotifyPropertyChanged, IViewFor { - /// - /// The backer for DisplayName. - /// - private string _displayName = string.Empty; - - /// - /// The backer for DisplayAge. - /// - private int _displayAge; - /// public event PropertyChangedEventHandler? PropertyChanged; /// public object? ViewModel { get; set; } - /// - /// Gets or sets the display name. - /// + /// Gets or sets the display name. public string DisplayName { - get => _displayName; + get => field; set { - if (_displayName == value) + if (field == value) { return; } - _displayName = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(DisplayName))); } - } + } = string.Empty; - /// - /// Gets or sets the display age. - /// + /// Gets or sets the display age. public int DisplayAge { - get => _displayAge; + get => field; set { - if (_displayAge == value) + if (field == value) { return; } - _displayAge = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(DisplayAge))); } } diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/TestViewModel.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/TestViewModel.cs index 6763f04..e95d426 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/TestViewModel.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/TestViewModel.cs @@ -12,56 +12,42 @@ namespace ReactiveUI.Binding.GeneratedCode.TestModels.TestModels; /// public class TestViewModel : INotifyPropertyChanged, INotifyPropertyChanging { - /// - /// The backer for Name. - /// - private string _name = string.Empty; - - /// - /// The backer for Age. - /// - private int _age; - /// public event PropertyChangedEventHandler? PropertyChanged; /// public event PropertyChangingEventHandler? PropertyChanging; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { - get => _name; + get => field; set { - if (_name == value) + if (field == value) { return; } PropertyChanging?.Invoke(this, new(nameof(Name))); - _name = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Name))); } - } + } = string.Empty; - /// - /// Gets or sets the age. - /// + /// Gets or sets the age. public int Age { - get => _age; + get => field; set { - if (_age == value) + if (field == value) { return; } PropertyChanging?.Invoke(this, new(nameof(Age))); - _age = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Age))); } } diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/WhenAnyTestFixture.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/WhenAnyTestFixture.cs index 2097d3f..19acaa1 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/WhenAnyTestFixture.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.TestModels/TestModels/WhenAnyTestFixture.cs @@ -12,282 +12,198 @@ namespace ReactiveUI.Binding.GeneratedCode.TestModels.TestModels; /// public class WhenAnyTestFixture : INotifyPropertyChanged { - /// - /// The backer for Value1. - /// - private string _value1 = string.Empty; - - /// - /// The backer for Value2. - /// - private string _value2 = string.Empty; - - /// - /// The backer for Value3. - /// - private string _value3 = string.Empty; - - /// - /// The backer for Value4. - /// - private string _value4 = string.Empty; - - /// - /// The backer for Value5. - /// - private string _value5 = string.Empty; - - /// - /// The backer for Value6. - /// - private string _value6 = string.Empty; - - /// - /// The backer for Value7. - /// - private string _value7 = string.Empty; - - /// - /// The backer for Value8. - /// - private string _value8 = string.Empty; - - /// - /// The backer for Value9. - /// - private string _value9 = string.Empty; - - /// - /// The backer for Value10. - /// - private string _value10 = string.Empty; - - /// - /// The backer for Value11. - /// - private string _value11 = string.Empty; - - /// - /// The backer for Value12. - /// - private string _value12 = string.Empty; - /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets value1. - /// + /// Gets or sets value1. public string Value1 { - get => _value1; + get => field; set { - if (_value1 == value) + if (field == value) { return; } - _value1 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Value1))); } - } + } = string.Empty; - /// - /// Gets or sets value2. - /// + /// Gets or sets value2. public string Value2 { - get => _value2; + get => field; set { - if (_value2 == value) + if (field == value) { return; } - _value2 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Value2))); } - } + } = string.Empty; - /// - /// Gets or sets value3. - /// + /// Gets or sets value3. public string Value3 { - get => _value3; + get => field; set { - if (_value3 == value) + if (field == value) { return; } - _value3 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Value3))); } - } + } = string.Empty; - /// - /// Gets or sets value4. - /// + /// Gets or sets value4. public string Value4 { - get => _value4; + get => field; set { - if (_value4 == value) + if (field == value) { return; } - _value4 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Value4))); } - } + } = string.Empty; - /// - /// Gets or sets value5. - /// + /// Gets or sets value5. public string Value5 { - get => _value5; + get => field; set { - if (_value5 == value) + if (field == value) { return; } - _value5 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Value5))); } - } + } = string.Empty; - /// - /// Gets or sets value6. - /// + /// Gets or sets value6. public string Value6 { - get => _value6; + get => field; set { - if (_value6 == value) + if (field == value) { return; } - _value6 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Value6))); } - } + } = string.Empty; - /// - /// Gets or sets value7. - /// + /// Gets or sets value7. public string Value7 { - get => _value7; + get => field; set { - if (_value7 == value) + if (field == value) { return; } - _value7 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Value7))); } - } + } = string.Empty; - /// - /// Gets or sets value8. - /// + /// Gets or sets value8. public string Value8 { - get => _value8; + get => field; set { - if (_value8 == value) + if (field == value) { return; } - _value8 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Value8))); } - } + } = string.Empty; - /// - /// Gets or sets value9. - /// + /// Gets or sets value9. public string Value9 { - get => _value9; + get => field; set { - if (_value9 == value) + if (field == value) { return; } - _value9 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Value9))); } - } + } = string.Empty; - /// - /// Gets or sets value10. - /// + /// Gets or sets value10. public string Value10 { - get => _value10; + get => field; set { - if (_value10 == value) + if (field == value) { return; } - _value10 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Value10))); } - } + } = string.Empty; - /// - /// Gets or sets value11. - /// + /// Gets or sets value11. public string Value11 { - get => _value11; + get => field; set { - if (_value11 == value) + if (field == value) { return; } - _value11 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Value11))); } - } + } = string.Empty; - /// - /// Gets or sets value12. - /// + /// Gets or sets value12. public string Value12 { - get => _value12; + get => field; set { - if (_value12 == value) + if (field == value) { return; } - _value12 = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(Value12))); } - } + } = string.Empty; } diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/AssemblySetup.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/AssemblySetup.cs index 891c0eb..3ed7a09 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/AssemblySetup.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/AssemblySetup.cs @@ -8,20 +8,16 @@ namespace ReactiveUI.Binding.GeneratedCode.Tests; -/// -/// Assembly-level setup for the generated code test project. -/// +/// Assembly-level setup for the generated code test project. public static class AssemblySetup { - /// - /// Initializes the RxBinding builder for generated code tests. - /// + /// Initializes the RxBinding builder for generated code tests. [Before(Assembly)] public static void Initialize() { RxBindingBuilder.ResetForTesting(); var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - builder.WithCoreServices(); - builder.BuildApp(); + _ = builder.WithCoreServices(); + _ = builder.BuildApp(); } } diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/BindCommandTests.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/BindCommandTests.cs index 786c482..c88e9d4 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/BindCommandTests.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/BindCommandTests.cs @@ -7,34 +7,22 @@ namespace ReactiveUI.Binding.GeneratedCode.Tests.Binding; -/// -/// Tests that the source-generator-generated BindCommand code works correctly at runtime. -/// +/// Tests that the source-generator-generated BindCommand code works correctly at runtime. public class BindCommandTests { - /// - /// The expression-parameter test item value. - /// + /// The expression-parameter test item value. private const string TestItem = "TestItem"; - /// - /// The observable command-parameter value. - /// + /// The observable command-parameter value. private const string ObsParam = "obs-param"; - /// - /// The updated observable command-parameter value. - /// + /// The updated observable command-parameter value. private const string UpdatedValue = "updated"; - /// - /// The number of clicks performed in the multiple-clicks test. - /// + /// The number of clicks performed in the multiple-clicks test. private const int ExpectedClickCount = 3; - /// - /// Verifies that clicking the button executes the bound command (command set before binding). - /// + /// Verifies that clicking the button executes the bound command (command set before binding). /// A task representing the asynchronous test operation. [Test] public async Task BasicNoParam_CommandSetBeforeBinding_ExecutesOnClick() @@ -51,9 +39,7 @@ public async Task BasicNoParam_CommandSetBeforeBinding_ExecutesOnClick() await Assert.That(command.ExecuteCount).IsEqualTo(1); } - /// - /// Verifies that clicking the button executes the bound command (command set after binding). - /// + /// Verifies that clicking the button executes the bound command (command set after binding). /// A task representing the asynchronous test operation. [Test] public async Task BasicNoParam_CommandSetAfterBinding_ExecutesOnClick() @@ -70,9 +56,7 @@ public async Task BasicNoParam_CommandSetAfterBinding_ExecutesOnClick() await Assert.That(command.ExecuteCount).IsEqualTo(1); } - /// - /// Verifies that when the command is null, clicking the button does not throw. - /// + /// Verifies that when the command is null, clicking the button does not throw. /// A task representing the asynchronous test operation. [Test] public async Task BasicNoParam_NullCommand_ClickDoesNotThrow() @@ -86,9 +70,7 @@ public async Task BasicNoParam_NullCommand_ClickDoesNotThrow() await Assert.That(action).ThrowsNothing(); } - /// - /// Verifies that when the command changes, the new command is executed on click. - /// + /// Verifies that when the command changes, the new command is executed on click. /// A task representing the asynchronous test operation. [Test] public async Task BasicNoParam_CommandChanges_NewCommandExecutes() @@ -111,9 +93,7 @@ public async Task BasicNoParam_CommandChanges_NewCommandExecutes() await Assert.That(first.ExecuteCount).IsEqualTo(1); // no longer wired } - /// - /// Verifies that disposing the binding stops command execution on click. - /// + /// Verifies that disposing the binding stops command execution on click. /// A task representing the asynchronous test operation. [Test] public async Task BasicNoParam_Dispose_StopsExecution() @@ -133,9 +113,7 @@ public async Task BasicNoParam_Dispose_StopsExecution() await Assert.That(command.ExecuteCount).IsEqualTo(1); } - /// - /// Verifies that when CanExecute returns false, the command is not executed. - /// + /// Verifies that when CanExecute returns false, the command is not executed. /// A task representing the asynchronous test operation. [Test] public async Task BasicNoParam_CanExecuteFalse_CommandNotExecuted() @@ -151,9 +129,7 @@ public async Task BasicNoParam_CanExecuteFalse_CommandNotExecuted() await Assert.That(command.ExecuteCount).IsEqualTo(0); } - /// - /// Verifies that the expression parameter is passed to the command on click. - /// + /// Verifies that the expression parameter is passed to the command on click. /// A task representing the asynchronous test operation. [Test] public async Task ExpressionParam_PassesParameterToCommand() @@ -194,9 +170,7 @@ public async Task ExpressionParam_ParameterCapturedAtCommandBindTime() await Assert.That(command.LastParameter).IsEqualTo("AtCommandSetTime"); } - /// - /// Verifies that the observable parameter is passed to the command on click. - /// + /// Verifies that the observable parameter is passed to the command on click. /// A task representing the asynchronous test operation. [Test] public async Task ObservableParam_PassesParameterToCommand() @@ -214,9 +188,7 @@ public async Task ObservableParam_PassesParameterToCommand() await Assert.That(command.LastParameter).IsEqualTo("observable-param"); } - /// - /// Verifies that clicking the button 3 times results in 3 executions. - /// + /// Verifies that clicking the button 3 times results in 3 executions. /// A task representing the asynchronous test operation. [Test] public async Task BasicNoParam_MultipleClicks_ExecutesMultipleTimes() @@ -235,9 +207,7 @@ public async Task BasicNoParam_MultipleClicks_ExecutesMultipleTimes() await Assert.That(command.ExecuteCount).IsEqualTo(ExpectedClickCount); } - /// - /// Verifies that setting command then null, then clicking does not throw. - /// + /// Verifies that setting command then null, then clicking does not throw. /// A task representing the asynchronous test operation. [Test] public async Task BasicNoParam_CommandSetToNull_ClickDoesNotThrow() @@ -255,9 +225,7 @@ public async Task BasicNoParam_CommandSetToNull_ClickDoesNotThrow() await Assert.That(command.ExecuteCount).IsEqualTo(0); } - /// - /// Verifies that pushing a new value to the observable parameter is used on click. - /// + /// Verifies that pushing a new value to the observable parameter is used on click. /// A task representing the asynchronous test operation. [Test] public async Task ObservableParam_ParameterUpdates_UsesLatestValue() @@ -276,9 +244,7 @@ public async Task ObservableParam_ParameterUpdates_UsesLatestValue() await Assert.That(command.LastParameter).IsEqualTo("latest"); } - /// - /// Verifies that a custom event fires and the command executes. - /// + /// Verifies that a custom event fires and the command executes. /// A task representing the asynchronous test operation. [Test] public async Task CustomEvent_ExecutesOnCustomEvent() @@ -295,9 +261,7 @@ public async Task CustomEvent_ExecutesOnCustomEvent() await Assert.That(command.ExecuteCount).IsEqualTo(1); } - /// - /// Verifies that a deep command path (Child.SaveCommand) executes. - /// + /// Verifies that a deep command path (Child.SaveCommand) executes. /// A task representing the asynchronous test operation. [Test] public async Task DeepCommandPath_CommandExecutes() @@ -315,9 +279,7 @@ public async Task DeepCommandPath_CommandExecutes() await Assert.That(command.ExecuteCount).IsEqualTo(1); } - /// - /// Verifies that when the child is replaced, the new child's command is wired. - /// + /// Verifies that when the child is replaced, the new child's command is wired. /// A task representing the asynchronous test operation. [Test] public async Task DeepCommandPath_ChildReplaced_NewCommandExecutes() @@ -341,9 +303,7 @@ public async Task DeepCommandPath_ChildReplaced_NewCommandExecutes() await Assert.That(oldCommand.ExecuteCount).IsEqualTo(0); } - /// - /// Verifies that disposing twice does not throw. - /// + /// Verifies that disposing twice does not throw. /// A task representing the asynchronous test operation. [Test] public async Task BasicNoParam_DoubleDispose_DoesNotThrow() @@ -360,10 +320,7 @@ public async Task BasicNoParam_DoubleDispose_DoesNotThrow() } // ── EventEnabled (Click + Enabled, no Command property) ───────────── - - /// - /// Verifies that clicking executes the command via event+Enabled binding. - /// + /// Verifies that clicking executes the command via event+Enabled binding. /// A task representing the asynchronous test operation. [Test] public async Task EventEnabled_ClickExecutesCommand() @@ -379,9 +336,7 @@ public async Task EventEnabled_ClickExecutesCommand() await Assert.That(command.ExecuteCount).IsEqualTo(1); } - /// - /// Verifies that the Enabled property is synchronized with CanExecute. - /// + /// Verifies that the Enabled property is synchronized with CanExecute. /// A task representing the asynchronous test operation. [Test] public async Task EventEnabled_EnabledSyncedWithCanExecute() @@ -395,9 +350,7 @@ public async Task EventEnabled_EnabledSyncedWithCanExecute() await Assert.That(view.SaveButton.Enabled).IsFalse(); } - /// - /// Verifies that the Enabled property becomes false when the command is null. - /// + /// Verifies that the Enabled property becomes false when the command is null. /// A task representing the asynchronous test operation. [Test] public async Task EventEnabled_NullCommand_DisablesControl() @@ -410,9 +363,7 @@ public async Task EventEnabled_NullCommand_DisablesControl() await Assert.That(view.SaveButton.Enabled).IsFalse(); } - /// - /// Verifies that disposing the binding stops command execution. - /// + /// Verifies that disposing the binding stops command execution. /// A task representing the asynchronous test operation. [Test] public async Task EventEnabled_Dispose_StopsExecution() @@ -432,9 +383,7 @@ public async Task EventEnabled_Dispose_StopsExecution() await Assert.That(command.ExecuteCount).IsEqualTo(1); } - /// - /// Verifies that CanExecute=false prevents execution via event+Enabled binding. - /// + /// Verifies that CanExecute=false prevents execution via event+Enabled binding. /// A task representing the asynchronous test operation. [Test] public async Task EventEnabled_CanExecuteFalse_DoesNotExecute() @@ -450,9 +399,7 @@ public async Task EventEnabled_CanExecuteFalse_DoesNotExecute() await Assert.That(command.ExecuteCount).IsEqualTo(0); } - /// - /// Verifies event+Enabled binding with an expression parameter. - /// + /// Verifies event+Enabled binding with an expression parameter. /// A task representing the asynchronous test operation. [Test] public async Task EventEnabledExprParam_PassesParameter() @@ -469,9 +416,7 @@ public async Task EventEnabledExprParam_PassesParameter() await Assert.That(command.LastParameter).IsEqualTo(TestItem); } - /// - /// Verifies event+Enabled binding with an observable parameter. - /// + /// Verifies event+Enabled binding with an observable parameter. /// A task representing the asynchronous test operation. [Test] public async Task EventEnabledObsParam_PassesParameter() @@ -489,9 +434,7 @@ public async Task EventEnabledObsParam_PassesParameter() await Assert.That(command.LastParameter).IsEqualTo(ObsParam); } - /// - /// Verifies event+Enabled binding with observable parameter updates reactively. - /// + /// Verifies event+Enabled binding with observable parameter updates reactively. /// A task representing the asynchronous test operation. [Test] public async Task EventEnabledObsParam_ParameterUpdates() @@ -511,10 +454,7 @@ public async Task EventEnabledObsParam_ParameterUpdates() } // ── CommandProperty (Command + CommandParameter, no event) ────────── - - /// - /// Verifies that binding sets the Command property on the control. - /// + /// Verifies that binding sets the Command property on the control. /// A task representing the asynchronous test operation. [Test] public async Task CommandProperty_SetsCommandOnControl() @@ -529,9 +469,7 @@ public async Task CommandProperty_SetsCommandOnControl() await Assert.That(view.SaveButton.Command).IsEqualTo(command); } - /// - /// Verifies that setting the command after binding updates the control. - /// + /// Verifies that setting the command after binding updates the control. /// A task representing the asynchronous test operation. [Test] public async Task CommandProperty_CommandSetAfterBinding_UpdatesControl() @@ -547,9 +485,7 @@ public async Task CommandProperty_CommandSetAfterBinding_UpdatesControl() await Assert.That(view.SaveButton.Command).IsEqualTo(command); } - /// - /// Verifies that changing the command updates the control's Command property. - /// + /// Verifies that changing the command updates the control's Command property. /// A task representing the asynchronous test operation. [Test] public async Task CommandProperty_CommandChanges_ControlUpdated() @@ -567,9 +503,7 @@ public async Task CommandProperty_CommandChanges_ControlUpdated() await Assert.That(view.SaveButton.Command).IsEqualTo(second); } - /// - /// Verifies that null command results in null on the control. - /// + /// Verifies that null command results in null on the control. /// A task representing the asynchronous test operation. [Test] public async Task CommandProperty_NullCommand_SetsControlCommandNull() @@ -582,9 +516,7 @@ public async Task CommandProperty_NullCommand_SetsControlCommandNull() await Assert.That(view.SaveButton.Command).IsNull(); } - /// - /// Verifies that expression parameter sets CommandParameter on the control. - /// + /// Verifies that expression parameter sets CommandParameter on the control. /// A task representing the asynchronous test operation. [Test] public async Task CommandPropertyExprParam_SetsCommandParameter() @@ -600,9 +532,7 @@ public async Task CommandPropertyExprParam_SetsCommandParameter() await Assert.That(view.SaveButton.CommandParameter).IsEqualTo(TestItem); } - /// - /// Verifies that observable parameter sets CommandParameter on the control. - /// + /// Verifies that observable parameter sets CommandParameter on the control. /// A task representing the asynchronous test operation. [Test] public async Task CommandPropertyObsParam_SetsCommandParameter() @@ -619,9 +549,7 @@ public async Task CommandPropertyObsParam_SetsCommandParameter() await Assert.That(view.SaveButton.CommandParameter).IsEqualTo(ObsParam); } - /// - /// Verifies that the observable parameter updates CommandParameter reactively. - /// + /// Verifies that the observable parameter updates CommandParameter reactively. /// A task representing the asynchronous test operation. [Test] public async Task CommandPropertyObsParam_ParameterUpdates() @@ -639,9 +567,7 @@ public async Task CommandPropertyObsParam_ParameterUpdates() await Assert.That(view.SaveButton.CommandParameter).IsEqualTo(UpdatedValue); } - /// - /// A simple implementation that tracks invocations for testing. - /// + /// A simple implementation that tracks invocations for testing. private sealed class TrackingCommand : ICommand { /// @@ -651,19 +577,13 @@ public event EventHandler? CanExecuteChanged remove { /* CanExecute never changes for this command. */ } } - /// - /// Gets or sets a value indicating whether returns . - /// + /// Gets or sets a value indicating whether returns . public bool CanExecuteResult { get; set; } = true; - /// - /// Gets the number of times has been called. - /// + /// Gets the number of times has been called. public int ExecuteCount { get; private set; } - /// - /// Gets the parameter passed to the most recent call. - /// + /// Gets the parameter passed to the most recent call. public object? LastParameter { get; private set; } /// diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/BindCompatTests.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/BindCompatTests.cs index 94eceda..d7cedb9 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/BindCompatTests.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/BindCompatTests.cs @@ -7,19 +7,13 @@ namespace ReactiveUI.Binding.GeneratedCode.Tests.Binding; -/// -/// Tests that the Bind compat alias (view-first two-way syntax) works correctly at runtime. -/// +/// Tests that the Bind compat alias (view-first two-way syntax) works correctly at runtime. public class BindCompatTests { - /// - /// The initial property value used across the binding tests. - /// + /// The initial property value used across the binding tests. private const string HelloValue = "Hello"; - /// - /// Verifies that Bind syncs the initial value from view model to view. - /// + /// Verifies that Bind syncs the initial value from view model to view. /// A task representing the asynchronous test operation. [Test] public async Task Bind_SyncsInitialValue() @@ -32,9 +26,7 @@ public async Task Bind_SyncsInitialValue() await Assert.That(view.DisplayName).IsEqualTo(HelloValue); } - /// - /// Verifies that Bind syncs changes from view model to view. - /// + /// Verifies that Bind syncs changes from view model to view. /// A task representing the asynchronous test operation. [Test] public async Task Bind_SyncsSourceToView() @@ -49,9 +41,7 @@ public async Task Bind_SyncsSourceToView() await Assert.That(view.DisplayName).IsEqualTo("World"); } - /// - /// Verifies that Bind syncs changes from view back to view model. - /// + /// Verifies that Bind syncs changes from view back to view model. /// A task representing the asynchronous test operation. [Test] public async Task Bind_SyncsViewToSource() @@ -66,9 +56,7 @@ public async Task Bind_SyncsViewToSource() await Assert.That(vm.Name).IsEqualTo("FromView"); } - /// - /// Verifies that disposing the Bind binding stops syncing. - /// + /// Verifies that disposing the Bind binding stops syncing. /// A task representing the asynchronous test operation. [Test] public async Task Bind_Disposal_StopsSyncing() diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/BindInteractionTests.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/BindInteractionTests.cs index a9d0bd1..36b9d50 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/BindInteractionTests.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/BindInteractionTests.cs @@ -6,24 +6,16 @@ namespace ReactiveUI.Binding.GeneratedCode.Tests.Binding; -/// -/// Tests that the source-generator-generated BindInteraction code works correctly at runtime. -/// +/// Tests that the source-generator-generated BindInteraction code works correctly at runtime. public class BindInteractionTests { - /// - /// The interaction input value used across the handler tests. - /// + /// The interaction input value used across the handler tests. private const string Question = "question"; - /// - /// The number of sequential Handle calls in the multiple-calls test. - /// + /// The number of sequential Handle calls in the multiple-calls test. private const int HandleCallCount = 5; - /// - /// Verifies that a task-based handler is registered and produces the expected output. - /// + /// Verifies that a task-based handler is registered and produces the expected output. /// A task representing the asynchronous test operation. [Test] public async Task TaskHandler_Handle_ReturnsExpectedOutput() @@ -38,9 +30,7 @@ public async Task TaskHandler_Handle_ReturnsExpectedOutput() await Assert.That(result).IsTrue(); } - /// - /// Verifies that an observable-based handler is registered and produces the expected output. - /// + /// Verifies that an observable-based handler is registered and produces the expected output. /// A task representing the asynchronous test operation. [Test] public async Task ObservableHandler_Handle_ReturnsExpectedOutput() @@ -55,9 +45,7 @@ public async Task ObservableHandler_Handle_ReturnsExpectedOutput() await Assert.That(result).IsTrue(); } - /// - /// Verifies that disposing the binding unregisters the handler so subsequent Handle calls throw. - /// + /// Verifies that disposing the binding unregisters the handler so subsequent Handle calls throw. /// A task representing the asynchronous test operation. [Test] public async Task TaskHandler_Dispose_UnregistersHandler() @@ -72,9 +60,7 @@ await Assert.That(() => vm.Confirm.Handle(Question)) .ThrowsExactly>(); } - /// - /// Verifies that when the VM's interaction property changes, the handler follows the new interaction. - /// + /// Verifies that when the VM's interaction property changes, the handler follows the new interaction. /// A task representing the asynchronous test operation. [Test] public async Task TaskHandler_InteractionPropertyChanges_HandlerFollowsNewInteraction() @@ -98,9 +84,7 @@ await Assert.That(() => originalInteraction.Handle("old")) await Assert.That(result).IsTrue(); } - /// - /// Verifies that a deep property path (Child.Confirm) interaction binding works. - /// + /// Verifies that a deep property path (Child.Confirm) interaction binding works. /// A task representing the asynchronous test operation. [Test] public async Task DeepPropertyPath_Handle_ReturnsExpectedOutput() @@ -115,9 +99,7 @@ public async Task DeepPropertyPath_Handle_ReturnsExpectedOutput() await Assert.That(result).IsTrue(); } - /// - /// Verifies that when Child is replaced, the handler follows the new child's interaction. - /// + /// Verifies that when Child is replaced, the handler follows the new child's interaction. /// A task representing the asynchronous test operation. [Test] public async Task DeepPropertyPath_ChildReplaced_HandlerFollowsNewChild() @@ -140,9 +122,7 @@ await Assert.That(() => originalChild.Confirm.Handle("old")) await Assert.That(result).IsTrue(); } - /// - /// Verifies that disposing the observable handler binding unregisters the handler. - /// + /// Verifies that disposing the observable handler binding unregisters the handler. /// A task representing the asynchronous test operation. [Test] public async Task ObservableHandler_Dispose_UnregistersHandler() @@ -157,9 +137,7 @@ await Assert.That(() => vm.Confirm.Handle(Question)) .ThrowsExactly>(); } - /// - /// Verifies that when the VM's interaction property changes, the observable handler follows the new interaction. - /// + /// Verifies that when the VM's interaction property changes, the observable handler follows the new interaction. /// A task representing the asynchronous test operation. [Test] public async Task ObservableHandler_InteractionPropertyChanges_HandlerFollows() @@ -182,9 +160,7 @@ await Assert.That(() => originalInteraction.Handle("old")) await Assert.That(result).IsTrue(); } - /// - /// Verifies that setting child to null on a deep path unregisters the handler. - /// + /// Verifies that setting child to null on a deep path unregisters the handler. /// A task representing the asynchronous test operation. [Test] public async Task DeepPropertyPath_ChildSetToNull_HandlerUnregisters() @@ -206,9 +182,7 @@ await Assert.That(() => child.Confirm.Handle(Question)) .ThrowsExactly>(); } - /// - /// Verifies that disposing twice does not throw. - /// + /// Verifies that disposing twice does not throw. /// A task representing the asynchronous test operation. [Test] public async Task TaskHandler_DoubleDispose_DoesNotThrow() @@ -223,9 +197,7 @@ public async Task TaskHandler_DoubleDispose_DoesNotThrow() await Assert.That(action).ThrowsNothing(); } - /// - /// Verifies that the interaction binding handles multiple sequential Handle calls correctly. - /// + /// Verifies that the interaction binding handles multiple sequential Handle calls correctly. /// A task representing the asynchronous test operation. [Test] public async Task TaskHandler_MultipleHandleCalls_AllReturnExpectedOutput() diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/BindOneWayTests.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/BindOneWayTests.cs index aec6b03..c0f351b 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/BindOneWayTests.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/BindOneWayTests.cs @@ -7,39 +7,25 @@ namespace ReactiveUI.Binding.GeneratedCode.Tests.Binding; -/// -/// Tests that the source-generator-generated BindOneWay code works correctly at runtime. -/// +/// Tests that the source-generator-generated BindOneWay code works correctly at runtime. public class BindOneWayTests { - /// - /// The initial string property value used across the binding tests. - /// + /// The initial string property value used across the binding tests. private const string HelloValue = "Hello"; - /// - /// The initial integer property test value. - /// + /// The initial integer property test value. private const int IntValue = 42; - /// - /// The updated integer property test value. - /// + /// The updated integer property test value. private const int UpdatedIntValue = 100; - /// - /// The initial double property test value. - /// + /// The initial double property test value. private const double DoubleValue = 3.14; - /// - /// The updated double property test value. - /// + /// The updated double property test value. private const double UpdatedDoubleValue = 2.71; - /// - /// Verifies that BindOneWay syncs the initial string property value. - /// + /// Verifies that BindOneWay syncs the initial string property value. /// A task representing the asynchronous test operation. [Test] public async Task StringProperty_SyncsInitialValue() @@ -52,9 +38,7 @@ public async Task StringProperty_SyncsInitialValue() await Assert.That(target.ViewProp1).IsEqualTo(HelloValue); } - /// - /// Verifies that BindOneWay syncs string property changes from source to target. - /// + /// Verifies that BindOneWay syncs string property changes from source to target. /// A task representing the asynchronous test operation. [Test] public async Task StringProperty_SyncsOnSourceChange() @@ -69,9 +53,7 @@ public async Task StringProperty_SyncsOnSourceChange() await Assert.That(target.ViewProp1).IsEqualTo("World"); } - /// - /// Verifies that BindOneWay syncs int property values. - /// + /// Verifies that BindOneWay syncs int property values. /// A task representing the asynchronous test operation. [Test] public async Task IntProperty_SyncsValues() @@ -88,9 +70,7 @@ public async Task IntProperty_SyncsValues() await Assert.That(target.ViewProp2).IsEqualTo(UpdatedIntValue); } - /// - /// Verifies that BindOneWay syncs double property values. - /// + /// Verifies that BindOneWay syncs double property values. /// A task representing the asynchronous test operation. [Test] public async Task DoubleProperty_SyncsValues() @@ -107,9 +87,7 @@ public async Task DoubleProperty_SyncsValues() await Assert.That(target.ViewProp3).IsEqualTo(UpdatedDoubleValue); } - /// - /// Verifies that BindOneWay syncs bool property values. - /// + /// Verifies that BindOneWay syncs bool property values. /// A task representing the asynchronous test operation. [Test] public async Task BoolProperty_SyncsValues() @@ -126,9 +104,7 @@ public async Task BoolProperty_SyncsValues() await Assert.That(target.ViewProp4).IsFalse(); } - /// - /// Verifies that disposing the binding stops syncing values. - /// + /// Verifies that disposing the binding stops syncing values. /// A task representing the asynchronous test operation. [Test] public async Task Disposal_StopsSyncing() diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/BindToTests.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/BindToTests.cs index 4c6b242..d23dd0b 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/BindToTests.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/BindToTests.cs @@ -8,19 +8,13 @@ namespace ReactiveUI.Binding.GeneratedCode.Tests.Binding; -/// -/// Runtime execution tests for generated BindTo bindings. -/// +/// Runtime execution tests for generated BindTo bindings. public class BindToTests { - /// - /// The initial observable value used across the binding tests. - /// + /// The initial observable value used across the binding tests. private const string InitialValue = "initial"; - /// - /// Verifies that BindTo applies the observable's current and subsequent values to the target property. - /// + /// Verifies that BindTo applies the observable's current and subsequent values to the target property. /// A task representing the asynchronous test operation. [Test] public async Task BindTo_String_PushesValuesToTarget() @@ -37,9 +31,7 @@ public async Task BindTo_String_PushesValuesToTarget() await Assert.That(target.ViewProp1).IsEqualTo("updated"); } - /// - /// Verifies that disposing a BindTo binding stops further updates to the target property. - /// + /// Verifies that disposing a BindTo binding stops further updates to the target property. /// A task representing the asynchronous test operation. [Test] public async Task BindTo_Disposed_StopsUpdating() diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/BindTwoWayTests.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/BindTwoWayTests.cs index 15b7618..ea7d18e 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/BindTwoWayTests.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/BindTwoWayTests.cs @@ -7,34 +7,25 @@ namespace ReactiveUI.Binding.GeneratedCode.Tests.Binding; -/// -/// Tests that the source-generator-generated BindTwoWay code works correctly at runtime. -/// +/// Tests that the source-generator-generated BindTwoWay code works correctly at runtime. public class BindTwoWayTests { - /// - /// The initial string property value used across the binding tests. - /// + /// The initial string property value used across the binding tests. private const string HelloValue = "Hello"; - /// - /// The initial integer property test value. - /// + /// The initial integer property test value. private const int IntValue = 42; - /// - /// The updated integer property test value. - /// + /// The updated integer property test value. private const int UpdatedIntValue = 100; - /// - /// The second updated integer property test value. - /// + /// The second updated integer property test value. private const int SecondIntValue = 200; - /// - /// Verifies that BindTwoWay syncs the initial value from source to target. - /// + /// The value written to the view side to prove the target-to-source direction. + private const string FromTargetValue = "FromTarget"; + + /// Verifies that BindTwoWay syncs the initial value from source to target. /// A task representing the asynchronous test operation. [Test] public async Task StringProperty_SyncsSourceToTarget() @@ -51,9 +42,7 @@ public async Task StringProperty_SyncsSourceToTarget() await Assert.That(target.ViewProp1).IsEqualTo("World"); } - /// - /// Verifies that BindTwoWay syncs changes from target back to source. - /// + /// Verifies that BindTwoWay syncs changes from target back to source. /// A task representing the asynchronous test operation. [Test] public async Task StringProperty_SyncsTargetToSource() @@ -63,14 +52,12 @@ public async Task StringProperty_SyncsTargetToSource() using var binding = BindTwoWayScenarios.StringProperty(source, target); - target.ViewProp1 = "FromTarget"; + target.ViewProp1 = FromTargetValue; - await Assert.That(source.Prop1).IsEqualTo("FromTarget"); + await Assert.That(source.Prop1).IsEqualTo(FromTargetValue); } - /// - /// Verifies that BindTwoWay syncs int property in both directions. - /// + /// Verifies that BindTwoWay syncs int property in both directions. /// A task representing the asynchronous test operation. [Test] public async Task IntProperty_SyncsBothDirections() @@ -89,9 +76,7 @@ public async Task IntProperty_SyncsBothDirections() await Assert.That(source.Prop2).IsEqualTo(SecondIntValue); } - /// - /// Verifies that disposing the two-way binding stops syncing in both directions. - /// + /// Verifies that disposing the two-way binding stops syncing in both directions. /// A task representing the asynchronous test operation. [Test] public async Task Disposal_StopsSyncing() @@ -107,7 +92,7 @@ public async Task Disposal_StopsSyncing() source.Prop1 = "AfterDisposal"; await Assert.That(target.ViewProp1).IsEqualTo(HelloValue); - target.ViewProp1 = "FromTarget"; + target.ViewProp1 = FromTargetValue; await Assert.That(source.Prop1).IsEqualTo("AfterDisposal"); } } diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/BindingEdgeCaseTests.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/BindingEdgeCaseTests.cs index 5357a9f..a304d2a 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/BindingEdgeCaseTests.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/BindingEdgeCaseTests.cs @@ -13,44 +13,28 @@ namespace ReactiveUI.Binding.GeneratedCode.Tests.Binding; /// public class BindingEdgeCaseTests { - /// - /// The initial deep-chain city value. - /// + /// The initial deep-chain city value. private const string Seattle = "Seattle"; - /// - /// The updated deep-chain city value. - /// + /// The updated deep-chain city value. private const string Portland = "Portland"; - /// - /// The pre-set source property value. - /// + /// The pre-set source property value. private const string PreSet = "PreSet"; - /// - /// The initial double property test value. - /// + /// The initial double property test value. private const double DoubleValue = 3.14; - /// - /// The updated double property test value. - /// + /// The updated double property test value. private const double UpdatedDoubleValue = 2.71; - /// - /// The square root of two double property test value. - /// + /// The square root of two double property test value. private const double SqrtTwo = 1.41; - /// - /// The number of rapid sequential changes in the rapid-changes test. - /// + /// The number of rapid sequential changes in the rapid-changes test. private const int RapidChangeCount = 100; - /// - /// Verifies that BindOneWay with a deep chain source property syncs the initial value. - /// + /// Verifies that BindOneWay with a deep chain source property syncs the initial value. /// A task representing the asynchronous test operation. [Test] public async Task BindOneWay_DeepChainSource_SyncsInitialValue() @@ -64,9 +48,7 @@ public async Task BindOneWay_DeepChainSource_SyncsInitialValue() await Assert.That(target.ViewProp1).IsEqualTo(Seattle); } - /// - /// Verifies that BindOneWay with a deep chain source property syncs nested changes. - /// + /// Verifies that BindOneWay with a deep chain source property syncs nested changes. /// A task representing the asynchronous test operation. [Test] public async Task BindOneWay_DeepChainSource_SyncsNestedChanges() @@ -82,9 +64,7 @@ public async Task BindOneWay_DeepChainSource_SyncsNestedChanges() await Assert.That(target.ViewProp1).IsEqualTo(Portland); } - /// - /// Verifies that BindOneWay with a deep chain re-subscribes on intermediate replacement. - /// + /// Verifies that BindOneWay with a deep chain re-subscribes on intermediate replacement. /// A task representing the asynchronous test operation. [Test] public async Task BindOneWay_DeepChainSource_IntermediateReplacement() @@ -105,10 +85,7 @@ public async Task BindOneWay_DeepChainSource_IntermediateReplacement() await Assert.That(target.ViewProp1).IsEqualTo("Eugene"); } - /// - /// Verifies that multiple BindOneWay bindings to the same target property - /// both function correctly (last write wins). - /// + /// Verifies that multiple BindOneWay bindings to the same target property both function correctly (last write wins). /// A task representing the asynchronous test operation. [Test] public async Task BindOneWay_MultipleBindingsToSameTarget() @@ -131,9 +108,7 @@ public async Task BindOneWay_MultipleBindingsToSameTarget() await Assert.That(target.ViewProp5).IsEqualTo("Updated5"); } - /// - /// Verifies that BindTwoWay handles rapid back-and-forth changes without infinite loop. - /// + /// Verifies that BindTwoWay handles rapid back-and-forth changes without infinite loop. /// A task representing the asynchronous test operation. [Test] public async Task BindTwoWay_RapidBackAndForth() @@ -157,9 +132,7 @@ public async Task BindTwoWay_RapidBackAndForth() await Assert.That(source.Prop1).IsEqualTo("D"); } - /// - /// Verifies that BindTwoWay syncs double property in both directions. - /// + /// Verifies that BindTwoWay syncs double property in both directions. /// A task representing the asynchronous test operation. [Test] public async Task BindTwoWay_DoubleProperty_SyncsBothDirections() @@ -178,9 +151,7 @@ public async Task BindTwoWay_DoubleProperty_SyncsBothDirections() await Assert.That(source.Prop3).IsEqualTo(SqrtTwo); } - /// - /// Verifies that BindTwoWay syncs bool property in both directions. - /// + /// Verifies that BindTwoWay syncs bool property in both directions. /// A task representing the asynchronous test operation. [Test] public async Task BindTwoWay_BoolProperty_SyncsBothDirections() @@ -199,9 +170,7 @@ public async Task BindTwoWay_BoolProperty_SyncsBothDirections() await Assert.That(source.Prop4).IsTrue(); } - /// - /// Verifies that disposing a BindOneWay with deep chain source stops syncing. - /// + /// Verifies that disposing a BindOneWay with deep chain source stops syncing. /// A task representing the asynchronous test operation. [Test] public async Task BindOneWay_DeepChainSource_Disposal() @@ -237,10 +206,7 @@ public async Task BindOneWay_SourcePropertySetBeforeBinding_SyncsOnSubscription( await Assert.That(target.ViewProp1).IsEqualTo(PreSet); } - /// - /// Verifies that BindTwoWay correctly syncs a pre-set source value and then - /// supports bidirectional changes after binding. - /// + /// Verifies that BindTwoWay correctly syncs a pre-set source value and then supports bidirectional changes after binding. /// A task representing the asynchronous test operation. [Test] public async Task BindTwoWay_SourcePropertySetBeforeBinding_SyncsAndBiDirectional() @@ -261,9 +227,7 @@ public async Task BindTwoWay_SourcePropertySetBeforeBinding_SyncsAndBiDirectiona await Assert.That(target.ViewProp1).IsEqualTo("FromSource"); } - /// - /// Verifies that BindOneWay handles rapid sequential changes without missing any. - /// + /// Verifies that BindOneWay handles rapid sequential changes without missing any. /// A task representing the asynchronous test operation. [Test] public async Task BindOneWay_RapidChanges_AllSynced() diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/OneWayBindCompatTests.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/OneWayBindCompatTests.cs index faa3ac0..497ee78 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/OneWayBindCompatTests.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/Binding/OneWayBindCompatTests.cs @@ -7,19 +7,13 @@ namespace ReactiveUI.Binding.GeneratedCode.Tests.Binding; -/// -/// Tests that the OneWayBind compat alias (view-first syntax) works correctly at runtime. -/// +/// Tests that the OneWayBind compat alias (view-first syntax) works correctly at runtime. public class OneWayBindCompatTests { - /// - /// The initial property value used across the binding tests. - /// + /// The initial property value used across the binding tests. private const string HelloValue = "Hello"; - /// - /// Verifies that OneWayBind syncs the initial value from view model to view. - /// + /// Verifies that OneWayBind syncs the initial value from view model to view. /// A task representing the asynchronous test operation. [Test] public async Task OneWayBind_SyncsInitialValue() @@ -32,9 +26,7 @@ public async Task OneWayBind_SyncsInitialValue() await Assert.That(view.DisplayName).IsEqualTo(HelloValue); } - /// - /// Verifies that OneWayBind syncs changes from view model to view. - /// + /// Verifies that OneWayBind syncs changes from view model to view. /// A task representing the asynchronous test operation. [Test] public async Task OneWayBind_SyncsOnSourceChange() @@ -49,9 +41,7 @@ public async Task OneWayBind_SyncsOnSourceChange() await Assert.That(view.DisplayName).IsEqualTo("World"); } - /// - /// Verifies that disposing the OneWayBind binding stops syncing. - /// + /// Verifies that disposing the OneWayBind binding stops syncing. /// A task representing the asynchronous test operation. [Test] public async Task OneWayBind_Disposal_StopsSyncing() diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenAny/WhenAnyTests.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenAny/WhenAnyTests.cs index 1434921..7566de4 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenAny/WhenAnyTests.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenAny/WhenAnyTests.cs @@ -7,29 +7,22 @@ namespace ReactiveUI.Binding.GeneratedCode.Tests.WhenAny; -/// -/// Tests that the source-generator-generated WhenAny code (IObservedChange wrapper) works correctly at runtime. -/// +/// Tests that the source-generator-generated WhenAny code (IObservedChange wrapper) works correctly at runtime. public class WhenAnyTests { - /// - /// The initial name value used across the WhenAny tests. - /// + /// The initial name value used across the WhenAny tests. private const string InitialName = "Initial"; - /// - /// The expected emission count after an initial value plus one change. - /// + /// The expected emission count after an initial value plus one change. private const int ExpectedEmissionCount = 2; - /// - /// The updated age value used in change-emission tests. - /// + /// The updated age value used in change-emission tests. private const int AgeValue = 25; - /// - /// Verifies that a single-property WhenAny with value selector emits the initial value. - /// + /// The age used by the two-property fixtures in these tests. + private const int AdultAge = 30; + + /// Verifies that a single-property WhenAny with value selector emits the initial value. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_EmitsInitialValue() @@ -44,9 +37,7 @@ public async Task SingleProperty_EmitsInitialValue() await Assert.That(values[0]).IsEqualTo(InitialName); } - /// - /// Verifies that a single-property WhenAny emits on property change. - /// + /// Verifies that a single-property WhenAny emits on property change. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_EmitsOnChange() @@ -63,9 +54,7 @@ public async Task SingleProperty_EmitsOnChange() await Assert.That(values).Contains("Changed"); } - /// - /// Verifies that the IObservedChange wrapper provides Sender and Value. - /// + /// Verifies that the IObservedChange wrapper provides Sender and Value. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_IObservedChange_HasSenderAndValue() @@ -81,14 +70,12 @@ public async Task SingleProperty_IObservedChange_HasSenderAndValue() await Assert.That(changes[0].Sender).IsEqualTo(vm); } - /// - /// Verifies that two-property WhenAny with a selector emits the combined initial value. - /// + /// Verifies that two-property WhenAny with a selector emits the combined initial value. /// A task representing the asynchronous test operation. [Test] public async Task TwoProperties_EmitsInitialCombinedValue() { - var vm = new TestViewModel { Name = "Alice", Age = 30 }; + var vm = new TestViewModel { Name = "Alice", Age = AdultAge }; var values = new List(); using var sub = WhenAnyScenarios.TwoProperties_NameAge(vm) @@ -98,14 +85,12 @@ public async Task TwoProperties_EmitsInitialCombinedValue() await Assert.That(values[0]).IsEqualTo("Alice_30"); } - /// - /// Verifies that two-property WhenAny emits when either property changes. - /// + /// Verifies that two-property WhenAny emits when either property changes. /// A task representing the asynchronous test operation. [Test] public async Task TwoProperties_EmitsOnEitherChange() { - var vm = new TestViewModel { Name = "Alice", Age = 30 }; + var vm = new TestViewModel { Name = "Alice", Age = AdultAge }; var values = new List(); using var sub = WhenAnyScenarios.TwoProperties_NameAge(vm) @@ -120,9 +105,7 @@ public async Task TwoProperties_EmitsOnEitherChange() await Assert.That(values[^1]).IsEqualTo("Bob_25"); } - /// - /// Verifies that disposing the WhenAny subscription stops listening for changes. - /// + /// Verifies that disposing the WhenAny subscription stops listening for changes. /// A task representing the asynchronous test operation. [Test] public async Task Disposal_StopsListening() diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenAnyObservable/WhenAnyObservableTests.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenAnyObservable/WhenAnyObservableTests.cs index f907c9d..6cc36e0 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenAnyObservable/WhenAnyObservableTests.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenAnyObservable/WhenAnyObservableTests.cs @@ -8,24 +8,16 @@ namespace ReactiveUI.Binding.GeneratedCode.Tests.WhenAnyObservable; -/// -/// Tests that the source-generator-generated WhenAnyObservable code (Switch/Merge) works correctly at runtime. -/// +/// Tests that the source-generator-generated WhenAnyObservable code (Switch/Merge) works correctly at runtime. public class WhenAnyObservableTests { - /// - /// The value emitted from the first observable. - /// + /// The value emitted from the first observable. private const string From1 = "From1"; - /// - /// The value emitted from the second observable. - /// + /// The value emitted from the second observable. private const string From2 = "From2"; - /// - /// Verifies that single observable Switch pattern emits inner values. - /// + /// Verifies that single observable Switch pattern emits inner values. /// A task representing the asynchronous test operation. [Test] public async Task SingleObservable_Switch_EmitsInnerValues() @@ -42,9 +34,7 @@ public async Task SingleObservable_Switch_EmitsInnerValues() await Assert.That(values).Contains("Hello"); } - /// - /// Verifies that single observable Switch pattern resubscribes when the observable property changes. - /// + /// Verifies that single observable Switch pattern resubscribes when the observable property changes. /// A task representing the asynchronous test operation. [Test] public async Task SingleObservable_Switch_ResubscribesOnNewObservable() @@ -74,9 +64,7 @@ public async Task SingleObservable_Switch_ResubscribesOnNewObservable() await Assert.That(values).DoesNotContain("StaleFrom1"); } - /// - /// Verifies that two observable Merge pattern emits from both streams. - /// + /// Verifies that two observable Merge pattern emits from both streams. /// A task representing the asynchronous test operation. [Test] public async Task TwoObservables_Merge_EmitsBothStreams() @@ -96,9 +84,7 @@ public async Task TwoObservables_Merge_EmitsBothStreams() await Assert.That(values).Contains(From2); } - /// - /// Verifies that disposing the WhenAnyObservable subscription stops listening. - /// + /// Verifies that disposing the WhenAnyObservable subscription stops listening. /// A task representing the asynchronous test operation. [Test] public async Task Disposal_StopsListening() diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenAnyValue/WhenAnyValueEdgeCaseTests.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenAnyValue/WhenAnyValueEdgeCaseTests.cs index e3e5ce6..ac0cfa1 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenAnyValue/WhenAnyValueEdgeCaseTests.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenAnyValue/WhenAnyValueEdgeCaseTests.cs @@ -7,50 +7,34 @@ namespace ReactiveUI.Binding.GeneratedCode.Tests.WhenAnyValue; -/// -/// Edge case tests for WhenAnyValue covering disposal, deep chains, and multi-property -/// change emission scenarios. -/// +/// Edge case tests for WhenAnyValue covering disposal, deep chains, and multi-property change emission scenarios. public class WhenAnyValueEdgeCaseTests { - /// - /// The initial fixture value used in disposal and subscription tests. - /// + /// The initial fixture value used in disposal and subscription tests. private const string InitialValue = "Initial"; - /// - /// The initial nested city value used in deep-chain tests. - /// + /// The initial nested city value used in deep-chain tests. private const string Seattle = "Seattle"; - /// - /// The updated nested city value used in deep-chain tests. - /// + /// The updated nested city value used in deep-chain tests. private const string Portland = "Portland"; - /// - /// The expected emission count after an initial value plus one change. - /// + /// The expected emission count after an initial value plus one change. private const int ExpectedEmissionCount = 2; - /// - /// The number of property changes applied in the rapid-change test. - /// + /// The number of property changes applied in the rapid-change test. private const int ChangeCount = 100; - /// - /// The expected emission count after the initial value plus 100 changes. - /// + /// The expected emission count after the initial value plus 100 changes. private const int ExpectedRapidEmissionCount = 101; - /// - /// The expected emission count after the initial value plus 12 property changes. - /// + /// The expected emission count after the initial value plus 12 property changes. private const int ExpectedTwelvePropertyCount = 13; - /// - /// Verifies that disposing the WhenAnyValue subscription stops listening for changes. - /// + /// The value written to a property to trigger a change notification. + private const string ChangedValue = "Changed"; + + /// Verifies that disposing the WhenAnyValue subscription stops listening for changes. /// A task representing the asynchronous test operation. [Test] public async Task Disposal_StopsListening() @@ -69,9 +53,7 @@ public async Task Disposal_StopsListening() await Assert.That(values[0]).IsEqualTo(InitialValue); } - /// - /// Verifies that multi-property WhenAnyValue emits when either property changes. - /// + /// Verifies that multi-property WhenAnyValue emits when either property changes. /// A task representing the asynchronous test operation. [Test] public async Task TwoProperties_EmitsOnEitherChange() @@ -95,9 +77,7 @@ public async Task TwoProperties_EmitsOnEitherChange() await Assert.That(values[^1].property2).IsEqualTo("D"); } - /// - /// Verifies that deep chain WhenAnyValue emits the nested property value. - /// + /// Verifies that deep chain WhenAnyValue emits the nested property value. /// A task representing the asynchronous test operation. [Test] public async Task DeepChain_EmitsNestedPropertyValue() @@ -113,9 +93,7 @@ public async Task DeepChain_EmitsNestedPropertyValue() await Assert.That(values[0]).IsEqualTo(Seattle); } - /// - /// Verifies that deep chain WhenAnyValue emits on nested property change. - /// + /// Verifies that deep chain WhenAnyValue emits on nested property change. /// A task representing the asynchronous test operation. [Test] public async Task DeepChain_EmitsOnNestedPropertyChange() @@ -133,9 +111,7 @@ public async Task DeepChain_EmitsOnNestedPropertyChange() await Assert.That(values).Contains(Portland); } - /// - /// Verifies that deep chain WhenAnyValue re-subscribes on intermediate object replacement. - /// + /// Verifies that deep chain WhenAnyValue re-subscribes on intermediate object replacement. /// A task representing the asynchronous test operation. [Test] public async Task DeepChain_IntermediateObjectReplacement() @@ -158,9 +134,7 @@ public async Task DeepChain_IntermediateObjectReplacement() await Assert.That(values).Contains("Eugene"); } - /// - /// Verifies that WhenAnyValue with selector re-emits when properties change. - /// + /// Verifies that WhenAnyValue with selector re-emits when properties change. /// A task representing the asynchronous test operation. [Test] public async Task WithSelector_EmitsOnChange() @@ -178,9 +152,7 @@ public async Task WithSelector_EmitsOnChange() await Assert.That(values[^1]).IsEqualTo("Goodbye_World"); } - /// - /// Verifies that rapid sequential property changes are all captured by WhenAnyValue. - /// + /// Verifies that rapid sequential property changes are all captured by WhenAnyValue. /// A task representing the asynchronous test operation. [Test] public async Task RapidSequentialChanges_AllCaptured() @@ -201,10 +173,7 @@ public async Task RapidSequentialChanges_AllCaptured() await Assert.That(values[^1]).IsEqualTo("Value_99"); } - /// - /// Verifies that multiple subscriptions to the same WhenAnyValue observable - /// each receive independent emissions. - /// + /// Verifies that multiple subscriptions to the same WhenAnyValue observable each receive independent emissions. /// A task representing the asynchronous test operation. [Test] public async Task MultipleSubscriptions_ReceiveIndependentEmissions() @@ -218,12 +187,12 @@ public async Task MultipleSubscriptions_ReceiveIndependentEmissions() using var sub1 = obs.Subscribe(values1.Add); using var sub2 = obs.Subscribe(values2.Add); - fixture.Value1 = "Changed"; + fixture.Value1 = ChangedValue; await Assert.That(values1.Count).IsGreaterThanOrEqualTo(ExpectedEmissionCount); await Assert.That(values2.Count).IsGreaterThanOrEqualTo(ExpectedEmissionCount); - await Assert.That(values1).Contains("Changed"); - await Assert.That(values2).Contains("Changed"); + await Assert.That(values1).Contains(ChangedValue); + await Assert.That(values2).Contains(ChangedValue); } /// diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenAnyValue/WhenAnyValueExtendedTests.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenAnyValue/WhenAnyValueExtendedTests.cs index 928a3f8..d4165b2 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenAnyValue/WhenAnyValueExtendedTests.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenAnyValue/WhenAnyValueExtendedTests.cs @@ -13,14 +13,12 @@ namespace ReactiveUI.Binding.GeneratedCode.Tests.WhenAnyValue; /// public class WhenAnyValueExtendedTests { - /// - /// Verifies that four-property WhenAnyValue emits initial values. - /// + /// Verifies that four-property WhenAnyValue emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task FourProperties_EmitsInitialValues() { - var vm = new BigViewModel { Prop1 = "a", Prop2 = 2, Prop3 = 3.0, Prop4 = true }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenAnyValueExtendedScenarios.FourProperties(vm) @@ -29,21 +27,12 @@ public async Task FourProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that five-property WhenAnyValue emits initial values. - /// + /// Verifies that five-property WhenAnyValue emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task FiveProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e" - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenAnyValueExtendedScenarios.FiveProperties(vm) @@ -52,22 +41,12 @@ public async Task FiveProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that six-property WhenAnyValue emits initial values. - /// + /// Verifies that six-property WhenAnyValue emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task SixProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6 - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenAnyValueExtendedScenarios.SixProperties(vm) @@ -76,23 +55,12 @@ public async Task SixProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that seven-property WhenAnyValue emits initial values. - /// + /// Verifies that seven-property WhenAnyValue emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task SevenProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0 - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenAnyValueExtendedScenarios.SevenProperties(vm) @@ -101,24 +69,12 @@ public async Task SevenProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that eight-property WhenAnyValue emits initial values. - /// + /// Verifies that eight-property WhenAnyValue emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task EightProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenAnyValueExtendedScenarios.EightProperties(vm) @@ -127,25 +83,12 @@ public async Task EightProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that nine-property WhenAnyValue emits initial values. - /// + /// Verifies that nine-property WhenAnyValue emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task NineProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false, - Prop9 = "i" - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenAnyValueExtendedScenarios.NineProperties(vm) @@ -154,26 +97,12 @@ public async Task NineProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that ten-property WhenAnyValue emits initial values. - /// + /// Verifies that ten-property WhenAnyValue emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task TenProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false, - Prop9 = "i", - Prop10 = 10 - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenAnyValueExtendedScenarios.TenProperties(vm) @@ -182,27 +111,12 @@ public async Task TenProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that eleven-property WhenAnyValue emits initial values. - /// + /// Verifies that eleven-property WhenAnyValue emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task ElevenProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false, - Prop9 = "i", - Prop10 = 10, - Prop11 = 11.0 - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenAnyValueExtendedScenarios.ElevenProperties(vm) @@ -211,28 +125,12 @@ public async Task ElevenProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that twelve-property WhenAnyValue emits initial values. - /// + /// Verifies that twelve-property WhenAnyValue emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task TwelveProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false, - Prop9 = "i", - Prop10 = 10, - Prop11 = 11.0, - Prop12 = true - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenAnyValueExtendedScenarios.TwelveProperties(vm) @@ -241,29 +139,12 @@ public async Task TwelveProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that thirteen-property WhenAnyValue emits initial values. - /// + /// Verifies that thirteen-property WhenAnyValue emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task ThirteenProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false, - Prop9 = "i", - Prop10 = 10, - Prop11 = 11.0, - Prop12 = true, - Prop13 = "m" - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenAnyValueExtendedScenarios.ThirteenProperties(vm) @@ -272,30 +153,12 @@ public async Task ThirteenProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that fourteen-property WhenAnyValue emits initial values. - /// + /// Verifies that fourteen-property WhenAnyValue emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task FourteenProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false, - Prop9 = "i", - Prop10 = 10, - Prop11 = 11.0, - Prop12 = true, - Prop13 = "m", - Prop14 = 14 - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenAnyValueExtendedScenarios.FourteenProperties(vm) @@ -304,31 +167,12 @@ public async Task FourteenProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that fifteen-property WhenAnyValue emits initial values. - /// + /// Verifies that fifteen-property WhenAnyValue emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task FifteenProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false, - Prop9 = "i", - Prop10 = 10, - Prop11 = 11.0, - Prop12 = true, - Prop13 = "m", - Prop14 = 14, - Prop15 = 15.0 - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenAnyValueExtendedScenarios.FifteenProperties(vm) @@ -337,32 +181,12 @@ public async Task FifteenProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that sixteen-property WhenAnyValue emits initial values. - /// + /// Verifies that sixteen-property WhenAnyValue emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task SixteenProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false, - Prop9 = "i", - Prop10 = 10, - Prop11 = 11.0, - Prop12 = true, - Prop13 = "m", - Prop14 = 14, - Prop15 = 15.0, - Prop16 = false - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenAnyValueExtendedScenarios.SixteenProperties(vm) @@ -371,32 +195,12 @@ public async Task SixteenProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that sixteen-property WhenAnyValue with a selector correctly combines all property values. - /// + /// Verifies that sixteen-property WhenAnyValue with a selector correctly combines all property values. /// A task representing the asynchronous test operation. [Test] public async Task WithSelector_SixteenProperties() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false, - Prop9 = "i", - Prop10 = 10, - Prop11 = 11.0, - Prop12 = true, - Prop13 = "m", - Prop14 = 14, - Prop15 = 15.0, - Prop16 = false - }; + var vm = BigViewModel.CreatePopulated(); var values = new List(); using var sub = WhenAnyValueExtendedScenarios.WithSelector_SixteenProperties(vm) @@ -406,9 +210,7 @@ public async Task WithSelector_SixteenProperties() await Assert.That(values[0]).IsNotNull(); } - /// - /// Verifies that deep chain WhenAnyValue emits the nested property value. - /// + /// Verifies that deep chain WhenAnyValue emits the nested property value. /// A task representing the asynchronous test operation. [Test] public async Task DeepChain_AddressCity() diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenAnyValue/WhenAnyValueTests.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenAnyValue/WhenAnyValueTests.cs index 47a8853..52c6937 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenAnyValue/WhenAnyValueTests.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenAnyValue/WhenAnyValueTests.cs @@ -7,34 +7,22 @@ namespace ReactiveUI.Binding.GeneratedCode.Tests.WhenAnyValue; -/// -/// Tests that the source-generator-generated WhenAnyValue code works correctly at runtime. -/// +/// Tests that the source-generator-generated WhenAnyValue code works correctly at runtime. public class WhenAnyValueTests { - /// - /// The expected emission count after an initial value plus one change. - /// + /// The expected emission count after an initial value plus one change. private const int ExpectedEmissionCount = 2; - /// - /// The second emission index. - /// + /// The second emission index. private const int SecondIndex = 2; - /// - /// The expected emission count after an initial value plus three changes. - /// + /// The expected emission count after an initial value plus three changes. private const int FourEmissionCount = 4; - /// - /// The third emission index. - /// + /// The third emission index. private const int ThirdIndex = 3; - /// - /// Verifies that single-property WhenAnyValue emits initial value and subsequent changes. - /// + /// Verifies that single-property WhenAnyValue emits initial value and subsequent changes. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_EmitsInitialAndChanges() @@ -54,9 +42,7 @@ public async Task SingleProperty_EmitsInitialAndChanges() await Assert.That(values).Contains("B"); } - /// - /// Verifies that two-property WhenAnyValue emits tuples. - /// + /// Verifies that two-property WhenAnyValue emits tuples. /// A task representing the asynchronous test operation. [Test] public async Task TwoProperties_EmitsTuples() @@ -72,9 +58,7 @@ public async Task TwoProperties_EmitsTuples() await Assert.That(values[0].property2).IsEqualTo("B"); } - /// - /// Verifies that three-property WhenAnyValue emits tuples. - /// + /// Verifies that three-property WhenAnyValue emits tuples. /// A task representing the asynchronous test operation. [Test] public async Task ThreeProperties_EmitsTuples() @@ -91,9 +75,7 @@ public async Task ThreeProperties_EmitsTuples() await Assert.That(values[0].property3).IsEqualTo("C"); } - /// - /// Verifies that WhenAnyValue with a selector projects values correctly. - /// + /// Verifies that WhenAnyValue with a selector projects values correctly. /// A task representing the asynchronous test operation. [Test] public async Task WithSelector_ProjectsValues() @@ -108,9 +90,7 @@ public async Task WithSelector_ProjectsValues() await Assert.That(values[0]).IsEqualTo("Hello_World"); } - /// - /// Verifies that WhenAnyValue emits all sequential changes. - /// + /// Verifies that WhenAnyValue emits all sequential changes. /// A task representing the asynchronous test operation. [Test] public async Task SequentialChanges_EmitsAll() diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenChanged/WhenChangedEdgeCaseTests.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenChanged/WhenChangedEdgeCaseTests.cs index b864022..1a13bff 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenChanged/WhenChangedEdgeCaseTests.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenChanged/WhenChangedEdgeCaseTests.cs @@ -13,41 +13,36 @@ namespace ReactiveUI.Binding.GeneratedCode.Tests.WhenChanged; /// public class WhenChangedEdgeCaseTests { - /// - /// The initial city value used by deep-chain tests. - /// + /// The initial city value used by deep-chain tests. private const string Seattle = "Seattle"; - /// - /// The replacement city value used by deep-chain tests. - /// + /// The replacement city value used by deep-chain tests. private const string Portland = "Portland"; - /// - /// The second replacement city value used by deep-chain tests. - /// + /// The second replacement city value used by deep-chain tests. private const string Eugene = "Eugene"; - /// - /// The simple property value used by multi-property tests. - /// + /// The simple property value used by multi-property tests. private const string HelloValue = "Hello"; - /// - /// The minimum number of emissions expected after a change. - /// + /// The minimum number of emissions expected after a change. private const int MinEmissionsAfterChange = 2; - /// - /// The initial age value used by integer-property tests. - /// + /// The initial age value used by integer-property tests. private const int AgeValue = 25; - /// - /// The updated age value used by integer-property tests. - /// + /// The updated age value used by integer-property tests. private const int UpdatedAgeValue = 30; + /// The value written to a property to trigger a change notification. + private const string ChangedValue = "Changed"; + + /// The value written after the subscription is disposed, which must not be observed. + private const string AfterDisposalValue = "AfterDisposal"; + + /// The initial name used by the fixtures in these tests. + private const string AliceName = "Alice"; + /// /// Verifies that replacing the intermediate object in a deep chain re-subscribes /// and emits the new object's property value. @@ -77,10 +72,7 @@ public async Task DeepChain_IntermediateObjectReplacement_ReSubscribes() await Assert.That(values).Contains(Eugene); } - /// - /// Verifies that after replacing the intermediate object, changes to the old - /// object's property are no longer observed. - /// + /// Verifies that after replacing the intermediate object, changes to the old object's property are no longer observed. /// A task representing the asynchronous test operation. [Test] public async Task DeepChain_IntermediateObjectReplacement_UnsubscribesOld() @@ -106,10 +98,7 @@ public async Task DeepChain_IntermediateObjectReplacement_UnsubscribesOld() await Assert.That(values[^1]).IsEqualTo("Second Ave"); } - /// - /// Verifies that DistinctUntilChanged filters out duplicate consecutive values - /// for single-property observation. - /// + /// Verifies that DistinctUntilChanged filters out duplicate consecutive values for single-property observation. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_DistinctUntilChanged_FiltersDuplicates() @@ -130,10 +119,7 @@ public async Task SingleProperty_DistinctUntilChanged_FiltersDuplicates() await Assert.That(values.Count).IsEqualTo(1); } - /// - /// Verifies that DistinctUntilChanged filters out duplicate consecutive values - /// in deep chain observation. - /// + /// Verifies that DistinctUntilChanged filters out duplicate consecutive values in deep chain observation. /// A task representing the asynchronous test operation. [Test] public async Task DeepChain_DistinctUntilChanged_FiltersDuplicates() @@ -154,10 +140,7 @@ public async Task DeepChain_DistinctUntilChanged_FiltersDuplicates() await Assert.That(values.Count).IsEqualTo(1); } - /// - /// Verifies that multi-property observation with a deep chain emits when - /// the nested property changes. - /// + /// Verifies that multi-property observation with a deep chain emits when the nested property changes. /// A task representing the asynchronous test operation. [Test] public async Task MultiProperty_WithDeepChain_EmitsOnNestedChange() @@ -180,10 +163,7 @@ public async Task MultiProperty_WithDeepChain_EmitsOnNestedChange() await Assert.That(values[^1].prop1).IsEqualTo(HelloValue); } - /// - /// Verifies that multi-property observation with a deep chain emits when - /// the simple property changes. - /// + /// Verifies that multi-property observation with a deep chain emits when the simple property changes. /// A task representing the asynchronous test operation. [Test] public async Task MultiProperty_WithDeepChain_EmitsOnSimpleChange() @@ -202,10 +182,7 @@ public async Task MultiProperty_WithDeepChain_EmitsOnSimpleChange() await Assert.That(values[^1].prop1).IsEqualTo("World"); } - /// - /// Verifies that multi-property observation with a deep chain re-subscribes - /// when the intermediate object is replaced. - /// + /// Verifies that multi-property observation with a deep chain re-subscribes when the intermediate object is replaced. /// A task representing the asynchronous test operation. [Test] public async Task MultiProperty_WithDeepChain_IntermediateReplacement() @@ -228,10 +205,7 @@ public async Task MultiProperty_WithDeepChain_IntermediateReplacement() await Assert.That(values[^1].city).IsEqualTo(Eugene); } - /// - /// Verifies that multiple subscriptions to the same WhenChanged observable - /// each receive independent emissions. - /// + /// Verifies that multiple subscriptions to the same WhenChanged observable each receive independent emissions. /// A task representing the asynchronous test operation. [Test] public async Task MultipleSubscriptions_ReceiveIndependentEmissions() @@ -245,17 +219,15 @@ public async Task MultipleSubscriptions_ReceiveIndependentEmissions() using var sub1 = obs.Subscribe(values1.Add); using var sub2 = obs.Subscribe(values2.Add); - vm.Name = "Changed"; + vm.Name = ChangedValue; await Assert.That(values1.Count).IsGreaterThanOrEqualTo(MinEmissionsAfterChange); await Assert.That(values2.Count).IsGreaterThanOrEqualTo(MinEmissionsAfterChange); - await Assert.That(values1).Contains("Changed"); - await Assert.That(values2).Contains("Changed"); + await Assert.That(values1).Contains(ChangedValue); + await Assert.That(values2).Contains(ChangedValue); } - /// - /// Verifies that disposing one subscription does not affect another. - /// + /// Verifies that disposing one subscription does not affect another. /// A task representing the asynchronous test operation. [Test] public async Task MultipleSubscriptions_DisposingOneDoesNotAffectOther() @@ -271,15 +243,13 @@ public async Task MultipleSubscriptions_DisposingOneDoesNotAffectOther() sub1.Dispose(); - vm.Name = "AfterDisposal"; + vm.Name = AfterDisposalValue; - await Assert.That(values1).DoesNotContain("AfterDisposal"); - await Assert.That(values2).Contains("AfterDisposal"); + await Assert.That(values1).DoesNotContain(AfterDisposalValue); + await Assert.That(values2).Contains(AfterDisposalValue); } - /// - /// Verifies that the deep chain disposal stops listening for nested property changes. - /// + /// Verifies that the deep chain disposal stops listening for nested property changes. /// A task representing the asynchronous test operation. [Test] public async Task DeepChain_Disposal_StopsListening() @@ -299,9 +269,7 @@ public async Task DeepChain_Disposal_StopsListening() await Assert.That(values[0]).IsEqualTo(Seattle); } - /// - /// Verifies that the deep chain disposal also stops listening after intermediate replacement. - /// + /// Verifies that the deep chain disposal also stops listening after intermediate replacement. /// A task representing the asynchronous test operation. [Test] public async Task DeepChain_Disposal_AfterIntermediateReplacement() @@ -321,9 +289,7 @@ public async Task DeepChain_Disposal_AfterIntermediateReplacement() await Assert.That(values).DoesNotContain(Eugene); } - /// - /// Verifies that the int property WhenChanged emits the initial value and changes. - /// + /// Verifies that the int property WhenChanged emits the initial value and changes. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_IntType_EmitsChanges() @@ -351,24 +317,21 @@ public async Task SingleProperty_IntType_EmitsChanges() [Test] public async Task DeepChain_NullForgiving_EmitsWhenChildSet() { - var host = new HostTestFixture { Child = new() { Name = "Alice" } }; + var host = new HostTestFixture { Child = new() { Name = AliceName } }; var values = new List(); using var sub = WhenChangedScenarios.DeepChain_ChildName(host) .Subscribe(values.Add); await Assert.That(values.Count).IsGreaterThanOrEqualTo(1); - await Assert.That(values[0]).IsEqualTo("Alice"); + await Assert.That(values[0]).IsEqualTo(AliceName); host.Child!.Name = "Bob"; await Assert.That(values).Contains("Bob"); } - /// - /// Verifies that deep chain with null-forgiving operator emits default - /// when the intermediate object is null. - /// + /// Verifies that deep chain with null-forgiving operator emits default when the intermediate object is null. /// A task representing the asynchronous test operation. [Test] public async Task DeepChain_NullForgiving_EmitsDefaultWhenChildNull() @@ -383,15 +346,12 @@ public async Task DeepChain_NullForgiving_EmitsDefaultWhenChildNull() await Assert.That(values.Count).IsGreaterThanOrEqualTo(1); } - /// - /// Verifies that deep chain with null-forgiving operator re-subscribes - /// when the intermediate object is replaced. - /// + /// Verifies that deep chain with null-forgiving operator re-subscribes when the intermediate object is replaced. /// A task representing the asynchronous test operation. [Test] public async Task DeepChain_NullForgiving_ReSubscribesOnReplacement() { - var host = new HostTestFixture { Child = new() { Name = "Alice" } }; + var host = new HostTestFixture { Child = new() { Name = AliceName } }; var values = new List(); using var sub = WhenChangedScenarios.DeepChain_ChildName(host) @@ -408,10 +368,7 @@ public async Task DeepChain_NullForgiving_ReSubscribesOnReplacement() await Assert.That(values).Contains("Dave"); } - /// - /// Verifies that deep chain with null-forgiving operator transitions - /// from null to non-null and starts observing. - /// + /// Verifies that deep chain with null-forgiving operator transitions from null to non-null and starts observing. /// A task representing the asynchronous test operation. [Test] public async Task DeepChain_NullForgiving_NullToNonNull() diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenChanged/WhenChangedExtendedTests.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenChanged/WhenChangedExtendedTests.cs index 66be152..673a2a5 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenChanged/WhenChangedExtendedTests.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenChanged/WhenChangedExtendedTests.cs @@ -13,21 +13,12 @@ namespace ReactiveUI.Binding.GeneratedCode.Tests.WhenChanged; /// public class WhenChangedExtendedTests { - /// - /// Verifies that five-property WhenChanged emits initial values. - /// + /// Verifies that five-property WhenChanged emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task FiveProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e" - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenChangedExtendedScenarios.FiveProperties(vm) @@ -36,22 +27,12 @@ public async Task FiveProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that six-property WhenChanged emits initial values. - /// + /// Verifies that six-property WhenChanged emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task SixProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6 - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenChangedExtendedScenarios.SixProperties(vm) @@ -60,23 +41,12 @@ public async Task SixProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that seven-property WhenChanged emits initial values. - /// + /// Verifies that seven-property WhenChanged emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task SevenProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0 - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenChangedExtendedScenarios.SevenProperties(vm) @@ -85,24 +55,12 @@ public async Task SevenProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that eight-property WhenChanged emits initial values. - /// + /// Verifies that eight-property WhenChanged emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task EightProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenChangedExtendedScenarios.EightProperties(vm) @@ -111,25 +69,12 @@ public async Task EightProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that nine-property WhenChanged emits initial values. - /// + /// Verifies that nine-property WhenChanged emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task NineProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false, - Prop9 = "i" - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenChangedExtendedScenarios.NineProperties(vm) @@ -138,26 +83,12 @@ public async Task NineProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that ten-property WhenChanged emits initial values. - /// + /// Verifies that ten-property WhenChanged emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task TenProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false, - Prop9 = "i", - Prop10 = 10 - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenChangedExtendedScenarios.TenProperties(vm) @@ -166,27 +97,12 @@ public async Task TenProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that eleven-property WhenChanged emits initial values. - /// + /// Verifies that eleven-property WhenChanged emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task ElevenProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false, - Prop9 = "i", - Prop10 = 10, - Prop11 = 11.0 - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenChangedExtendedScenarios.ElevenProperties(vm) @@ -195,28 +111,12 @@ public async Task ElevenProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that twelve-property WhenChanged emits initial values. - /// + /// Verifies that twelve-property WhenChanged emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task TwelveProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false, - Prop9 = "i", - Prop10 = 10, - Prop11 = 11.0, - Prop12 = true - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenChangedExtendedScenarios.TwelveProperties(vm) @@ -225,29 +125,12 @@ public async Task TwelveProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that thirteen-property WhenChanged emits initial values. - /// + /// Verifies that thirteen-property WhenChanged emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task ThirteenProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false, - Prop9 = "i", - Prop10 = 10, - Prop11 = 11.0, - Prop12 = true, - Prop13 = "m" - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenChangedExtendedScenarios.ThirteenProperties(vm) @@ -256,30 +139,12 @@ public async Task ThirteenProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that fourteen-property WhenChanged emits initial values. - /// + /// Verifies that fourteen-property WhenChanged emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task FourteenProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false, - Prop9 = "i", - Prop10 = 10, - Prop11 = 11.0, - Prop12 = true, - Prop13 = "m", - Prop14 = 14 - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenChangedExtendedScenarios.FourteenProperties(vm) @@ -288,31 +153,12 @@ public async Task FourteenProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that fifteen-property WhenChanged emits initial values. - /// + /// Verifies that fifteen-property WhenChanged emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task FifteenProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false, - Prop9 = "i", - Prop10 = 10, - Prop11 = 11.0, - Prop12 = true, - Prop13 = "m", - Prop14 = 14, - Prop15 = 15.0 - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenChangedExtendedScenarios.FifteenProperties(vm) @@ -321,32 +167,12 @@ public async Task FifteenProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that sixteen-property WhenChanged emits initial values. - /// + /// Verifies that sixteen-property WhenChanged emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task SixteenProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false, - Prop9 = "i", - Prop10 = 10, - Prop11 = 11.0, - Prop12 = true, - Prop13 = "m", - Prop14 = 14, - Prop15 = 15.0, - Prop16 = false - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenChangedExtendedScenarios.SixteenProperties(vm) @@ -355,32 +181,12 @@ public async Task SixteenProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that sixteen-property WhenChanged with a selector correctly combines all property values. - /// + /// Verifies that sixteen-property WhenChanged with a selector correctly combines all property values. /// A task representing the asynchronous test operation. [Test] public async Task WithSelector_SixteenProperties() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false, - Prop9 = "i", - Prop10 = 10, - Prop11 = 11.0, - Prop12 = true, - Prop13 = "m", - Prop14 = 14, - Prop15 = 15.0, - Prop16 = false - }; + var vm = BigViewModel.CreatePopulated(); var values = new List(); using var sub = WhenChangedExtendedScenarios.WithSelector_SixteenProperties(vm) diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenChanged/WhenChangedTests.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenChanged/WhenChangedTests.cs index a8a9e18..b5a8d65 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenChanged/WhenChangedTests.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenChanged/WhenChangedTests.cs @@ -7,79 +7,55 @@ namespace ReactiveUI.Binding.GeneratedCode.Tests.WhenChanged; -/// -/// Tests that the source-generator-generated WhenChanged code works correctly at runtime. -/// +/// Tests that the source-generator-generated WhenChanged code works correctly at runtime. public class WhenChangedTests { - /// - /// The initial name value used by single-property tests. - /// + /// The initial name value used by single-property tests. private const string InitialName = "Initial"; - /// - /// The minimum number of emissions expected after a single change. - /// + /// The minimum number of emissions expected after a single change. private const int MinEmissionsAfterChange = 2; - /// - /// The minimum number of emissions expected after two changes. - /// + /// The minimum number of emissions expected after two changes. private const int MinEmissionsAfterTwoChanges = 3; - /// - /// The minimum number of emissions expected after three sequential changes. - /// + /// The minimum number of emissions expected after three sequential changes. private const int MinEmissionsAfterThreeChanges = 4; - /// - /// The index of the second emission. - /// + /// The index of the second emission. private const int SecondEmissionIndex = 1; - /// - /// The index of the third emission. - /// + /// The index of the third emission. private const int ThirdEmissionIndex = 2; - /// - /// The index of the fourth emission. - /// + /// The index of the fourth emission. private const int FourthEmissionIndex = 3; - /// - /// The two-property test value for the integer property. - /// + /// The two-property test value for the integer property. private const int TwoPropIntValue = 42; - /// - /// The updated value for the integer property in two-property tests. - /// + /// The updated value for the integer property in two-property tests. private const int UpdatedIntValue = 2; - /// - /// The three-property test value for the integer property. - /// + /// The three-property test value for the integer property. private const int ThreePropIntValue = 10; - /// - /// The four-property test value for the integer property. - /// + /// The greeting value written to the observed string property. + private const string HelloValue = "Hello"; + + /// The city value written to the nested address in the deep-chain tests. + private const string SeattleCity = "Seattle"; + + /// The four-property test value for the integer property. private const int FourPropIntValue = 20; - /// - /// The three-property test value for the double property. - /// + /// The three-property test value for the double property. private const double ThreePropDoubleValue = 3.14; - /// - /// The four-property test value for the double property. - /// + /// The four-property test value for the double property. private const double FourPropDoubleValue = 2.71; - /// - /// Verifies that a single-property WhenChanged emits the initial value. - /// + /// Verifies that a single-property WhenChanged emits the initial value. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_EmitsInitialValue() @@ -94,9 +70,7 @@ public async Task SingleProperty_EmitsInitialValue() await Assert.That(values[0]).IsEqualTo(InitialName); } - /// - /// Verifies that a single-property WhenChanged emits when the property changes. - /// + /// Verifies that a single-property WhenChanged emits when the property changes. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_EmitsOnChange() @@ -113,9 +87,7 @@ public async Task SingleProperty_EmitsOnChange() await Assert.That(values).Contains("Changed"); } - /// - /// Verifies that a single-property WhenChanged emits all sequential changes. - /// + /// Verifies that a single-property WhenChanged emits all sequential changes. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_EmitsSequentialChanges() @@ -137,27 +109,23 @@ public async Task SingleProperty_EmitsSequentialChanges() await Assert.That(values[FourthEmissionIndex]).IsEqualTo("D"); } - /// - /// Verifies that a two-property WhenChanged emits the initial tuple. - /// + /// Verifies that a two-property WhenChanged emits the initial tuple. /// A task representing the asynchronous test operation. [Test] public async Task TwoProperties_EmitsInitialTuple() { - var vm = new BigViewModel { Prop1 = "Hello", Prop2 = TwoPropIntValue }; + var vm = new BigViewModel { Prop1 = HelloValue, Prop2 = TwoPropIntValue }; var values = new List<(string property1, int property2)>(); using var sub = WhenChangedScenarios.TwoProperties(vm) .Subscribe(values.Add); await Assert.That(values.Count).IsGreaterThanOrEqualTo(1); - await Assert.That(values[0].property1).IsEqualTo("Hello"); + await Assert.That(values[0].property1).IsEqualTo(HelloValue); await Assert.That(values[0].property2).IsEqualTo(TwoPropIntValue); } - /// - /// Verifies that a two-property WhenChanged emits when either property changes. - /// + /// Verifies that a two-property WhenChanged emits when either property changes. /// A task representing the asynchronous test operation. [Test] public async Task TwoProperties_EmitsOnEitherChange() @@ -181,9 +149,7 @@ public async Task TwoProperties_EmitsOnEitherChange() await Assert.That(values[^1].property2).IsEqualTo(UpdatedIntValue); } - /// - /// Verifies that three-property WhenChanged emits initial values. - /// + /// Verifies that three-property WhenChanged emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task ThreeProperties_EmitsInitialValues() @@ -200,9 +166,7 @@ public async Task ThreeProperties_EmitsInitialValues() await Assert.That(values[0].property3).IsEqualTo(ThreePropDoubleValue); } - /// - /// Verifies that four-property WhenChanged emits initial values. - /// + /// Verifies that four-property WhenChanged emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task FourProperties_EmitsInitialValues() @@ -220,14 +184,12 @@ public async Task FourProperties_EmitsInitialValues() await Assert.That(values[0].property4).IsTrue(); } - /// - /// Verifies that WhenChanged with a selector combines property values. - /// + /// Verifies that WhenChanged with a selector combines property values. /// A task representing the asynchronous test operation. [Test] public async Task WithSelector_CombinesValues() { - var vm = new BigViewModel { Prop1 = "Hello", Prop2 = TwoPropIntValue }; + var vm = new BigViewModel { Prop1 = HelloValue, Prop2 = TwoPropIntValue }; var values = new List(); using var sub = WhenChangedScenarios.WithSelector_TwoProperties(vm) @@ -237,33 +199,29 @@ public async Task WithSelector_CombinesValues() await Assert.That(values[0]).IsEqualTo("Hello_42"); } - /// - /// Verifies that deep chain WhenChanged emits the nested property value. - /// + /// Verifies that deep chain WhenChanged emits the nested property value. /// A task representing the asynchronous test operation. [Test] public async Task DeepChain_EmitsNestedPropertyValue() { var vm = new BigViewModel(); - vm.Address.City = "Seattle"; + vm.Address.City = SeattleCity; var values = new List(); using var sub = WhenChangedScenarios.DeepChain_AddressCity(vm) .Subscribe(values.Add); await Assert.That(values.Count).IsGreaterThanOrEqualTo(1); - await Assert.That(values[0]).IsEqualTo("Seattle"); + await Assert.That(values[0]).IsEqualTo(SeattleCity); } - /// - /// Verifies that deep chain WhenChanged emits when the nested property changes. - /// + /// Verifies that deep chain WhenChanged emits when the nested property changes. /// A task representing the asynchronous test operation. [Test] public async Task DeepChain_EmitsOnNestedPropertyChange() { var vm = new BigViewModel(); - vm.Address.City = "Seattle"; + vm.Address.City = SeattleCity; var values = new List(); using var sub = WhenChangedScenarios.DeepChain_AddressCity(vm) @@ -275,9 +233,7 @@ public async Task DeepChain_EmitsOnNestedPropertyChange() await Assert.That(values).Contains("Portland"); } - /// - /// Verifies that disposing the subscription stops listening for changes. - /// + /// Verifies that disposing the subscription stops listening for changes. /// A task representing the asynchronous test operation. [Test] public async Task Disposal_StopsListening() diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenChanged/WhenChangingEdgeCaseTests.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenChanged/WhenChangingEdgeCaseTests.cs index d40956a..3cc2ce7 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenChanged/WhenChangingEdgeCaseTests.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenChanged/WhenChangingEdgeCaseTests.cs @@ -7,35 +7,22 @@ namespace ReactiveUI.Binding.GeneratedCode.Tests.WhenChanged; -/// -/// Edge case tests for WhenChanging covering deep chains, multi-property change emission, -/// and disposal scenarios. -/// +/// Edge case tests for WhenChanging covering deep chains, multi-property change emission, and disposal scenarios. public class WhenChangingEdgeCaseTests { - /// - /// The initial city value used by deep-chain tests. - /// + /// The initial city value used by deep-chain tests. private const string Seattle = "Seattle"; - /// - /// The minimum number of emissions expected after a single change. - /// + /// The minimum number of emissions expected after a single change. private const int MinEmissionsAfterChange = 2; - /// - /// The minimum number of emissions expected after two changes. - /// + /// The minimum number of emissions expected after two changes. private const int MinEmissionsAfterTwoChanges = 3; - /// - /// The updated value for the integer property in two-property tests. - /// + /// The updated value for the integer property in two-property tests. private const int UpdatedIntValue = 2; - /// - /// Verifies that deep chain WhenChanging emits the initial nested property value. - /// + /// Verifies that deep chain WhenChanging emits the initial nested property value. /// A task representing the asynchronous test operation. [Test] public async Task DeepChain_EmitsInitialValue() @@ -74,9 +61,7 @@ public async Task DeepChain_EmitsBeforeNestedChange() await Assert.That(values[1]).IsEqualTo(Seattle); } - /// - /// Verifies that WhenChanging two-property emits when either property is about to change. - /// + /// Verifies that WhenChanging two-property emits when either property is about to change. /// A task representing the asynchronous test operation. [Test] public async Task TwoProperties_EmitsOnEitherChange() @@ -102,9 +87,7 @@ public async Task TwoProperties_EmitsOnEitherChange() await Assert.That(values[1].property2).IsEqualTo(1); } - /// - /// Verifies that disposing the WhenChanging deep chain subscription stops listening. - /// + /// Verifies that disposing the WhenChanging deep chain subscription stops listening. /// A task representing the asynchronous test operation. [Test] public async Task DeepChain_Disposal_StopsListening() @@ -124,9 +107,7 @@ public async Task DeepChain_Disposal_StopsListening() await Assert.That(values[0]).IsEqualTo(Seattle); } - /// - /// Verifies that WhenChanging multi-property emits sequential before-change values. - /// + /// Verifies that WhenChanging multi-property emits sequential before-change values. /// A task representing the asynchronous test operation. [Test] public async Task TwoProperties_SequentialChanges() diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenChanged/WhenChangingExtendedTests.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenChanged/WhenChangingExtendedTests.cs index dda31d4..d029afc 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenChanged/WhenChangingExtendedTests.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenChanged/WhenChangingExtendedTests.cs @@ -14,21 +14,12 @@ namespace ReactiveUI.Binding.GeneratedCode.Tests.WhenChanged; /// public class WhenChangingExtendedTests { - /// - /// Verifies that five-property WhenChanging emits initial values. - /// + /// Verifies that five-property WhenChanging emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task FiveProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e" - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenChangingExtendedScenarios.FiveProperties(vm) @@ -37,22 +28,12 @@ public async Task FiveProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that six-property WhenChanging emits initial values. - /// + /// Verifies that six-property WhenChanging emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task SixProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6 - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenChangingExtendedScenarios.SixProperties(vm) @@ -61,23 +42,12 @@ public async Task SixProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that seven-property WhenChanging emits initial values. - /// + /// Verifies that seven-property WhenChanging emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task SevenProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0 - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenChangingExtendedScenarios.SevenProperties(vm) @@ -86,24 +56,12 @@ public async Task SevenProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that eight-property WhenChanging emits initial values. - /// + /// Verifies that eight-property WhenChanging emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task EightProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenChangingExtendedScenarios.EightProperties(vm) @@ -112,25 +70,12 @@ public async Task EightProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that nine-property WhenChanging emits initial values. - /// + /// Verifies that nine-property WhenChanging emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task NineProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false, - Prop9 = "i" - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenChangingExtendedScenarios.NineProperties(vm) @@ -139,26 +84,12 @@ public async Task NineProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that ten-property WhenChanging emits initial values. - /// + /// Verifies that ten-property WhenChanging emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task TenProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false, - Prop9 = "i", - Prop10 = 10 - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenChangingExtendedScenarios.TenProperties(vm) @@ -167,27 +98,12 @@ public async Task TenProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that eleven-property WhenChanging emits initial values. - /// + /// Verifies that eleven-property WhenChanging emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task ElevenProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false, - Prop9 = "i", - Prop10 = 10, - Prop11 = 11.0 - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenChangingExtendedScenarios.ElevenProperties(vm) @@ -196,28 +112,12 @@ public async Task ElevenProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that twelve-property WhenChanging emits initial values. - /// + /// Verifies that twelve-property WhenChanging emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task TwelveProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false, - Prop9 = "i", - Prop10 = 10, - Prop11 = 11.0, - Prop12 = true - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenChangingExtendedScenarios.TwelveProperties(vm) @@ -226,29 +126,12 @@ public async Task TwelveProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that thirteen-property WhenChanging emits initial values. - /// + /// Verifies that thirteen-property WhenChanging emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task ThirteenProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false, - Prop9 = "i", - Prop10 = 10, - Prop11 = 11.0, - Prop12 = true, - Prop13 = "m" - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenChangingExtendedScenarios.ThirteenProperties(vm) @@ -257,30 +140,12 @@ public async Task ThirteenProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that fourteen-property WhenChanging emits initial values. - /// + /// Verifies that fourteen-property WhenChanging emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task FourteenProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false, - Prop9 = "i", - Prop10 = 10, - Prop11 = 11.0, - Prop12 = true, - Prop13 = "m", - Prop14 = 14 - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenChangingExtendedScenarios.FourteenProperties(vm) @@ -289,31 +154,12 @@ public async Task FourteenProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that fifteen-property WhenChanging emits initial values. - /// + /// Verifies that fifteen-property WhenChanging emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task FifteenProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false, - Prop9 = "i", - Prop10 = 10, - Prop11 = 11.0, - Prop12 = true, - Prop13 = "m", - Prop14 = 14, - Prop15 = 15.0 - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenChangingExtendedScenarios.FifteenProperties(vm) @@ -322,32 +168,12 @@ public async Task FifteenProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that sixteen-property WhenChanging emits initial values. - /// + /// Verifies that sixteen-property WhenChanging emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task SixteenProperties_EmitsInitialValues() { - var vm = new BigViewModel - { - Prop1 = "a", - Prop2 = 2, - Prop3 = 3.0, - Prop4 = true, - Prop5 = "e", - Prop6 = 6, - Prop7 = 7.0, - Prop8 = false, - Prop9 = "i", - Prop10 = 10, - Prop11 = 11.0, - Prop12 = true, - Prop13 = "m", - Prop14 = 14, - Prop15 = 15.0, - Prop16 = false - }; + var vm = BigViewModel.CreatePopulated(); var received = false; using var sub = WhenChangingExtendedScenarios.SixteenProperties(vm) @@ -356,9 +182,7 @@ public async Task SixteenProperties_EmitsInitialValues() await Assert.That(received).IsTrue(); } - /// - /// Verifies that deep chain WhenChanging emits the nested property value. - /// + /// Verifies that deep chain WhenChanging emits the nested property value. /// A task representing the asynchronous test operation. [Test] public async Task DeepChain_AddressCity() diff --git a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenChanged/WhenChangingTests.cs b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenChanged/WhenChangingTests.cs index eb99d93..e85f50c 100644 --- a/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenChanged/WhenChangingTests.cs +++ b/src/tests/ReactiveUI.Binding.GeneratedCode.Tests/WhenChanged/WhenChangingTests.cs @@ -13,54 +13,37 @@ namespace ReactiveUI.Binding.GeneratedCode.Tests.WhenChanged; /// public class WhenChangingTests { - /// - /// The initial name value used by single-property tests. - /// + /// The initial name value used by single-property tests. private const string InitialName = "Initial"; - /// - /// The minimum number of emissions expected after a single change. - /// + /// The minimum number of emissions expected after a single change. private const int MinEmissionsAfterChange = 2; - /// - /// The minimum number of emissions expected after two changes. - /// + /// The minimum number of emissions expected after two changes. private const int MinEmissionsAfterTwoChanges = 3; - /// - /// The index of the third emission. - /// + /// The index of the third emission. private const int ThirdEmissionIndex = 2; - /// - /// The two-property test value for the integer property. - /// + /// The two-property test value for the integer property. private const int TwoPropIntValue = 42; - /// - /// The three-property test value for the integer property. - /// + /// The three-property test value for the integer property. private const int ThreePropIntValue = 10; - /// - /// The four-property test value for the integer property. - /// + /// The four-property test value for the integer property. private const int FourPropIntValue = 20; - /// - /// The three-property test value for the double property. - /// + /// The three-property test value for the double property. private const double ThreePropDoubleValue = 3.14; - /// - /// The four-property test value for the double property. - /// + /// The four-property test value for the double property. private const double FourPropDoubleValue = 2.71; - /// - /// Verifies that a single-property WhenChanging emits the initial value. - /// + /// The value present before the change, which a before-change observation must report. + private const string BeforeValue = "Before"; + + /// Verifies that a single-property WhenChanging emits the initial value. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_EmitsInitialValue() @@ -83,7 +66,7 @@ public async Task SingleProperty_EmitsInitialValue() [Test] public async Task SingleProperty_EmitsBeforeChange() { - var vm = new TestViewModel { Name = "Before" }; + var vm = new TestViewModel { Name = BeforeValue }; var values = new List(); using var sub = WhenChangingScenarios.SingleProperty_Name(vm) @@ -94,13 +77,11 @@ public async Task SingleProperty_EmitsBeforeChange() // WhenChanging emits the value at the time of PropertyChanging event, // which is the old value (before the assignment). await Assert.That(values.Count).IsGreaterThanOrEqualTo(MinEmissionsAfterChange); - await Assert.That(values[0]).IsEqualTo("Before"); - await Assert.That(values[1]).IsEqualTo("Before"); + await Assert.That(values[0]).IsEqualTo(BeforeValue); + await Assert.That(values[1]).IsEqualTo(BeforeValue); } - /// - /// Verifies that a single-property WhenChanging emits sequential before-change values. - /// + /// Verifies that a single-property WhenChanging emits sequential before-change values. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_EmitsSequentialBeforeChangeValues() @@ -121,9 +102,7 @@ public async Task SingleProperty_EmitsSequentialBeforeChangeValues() await Assert.That(values[ThirdEmissionIndex]).IsEqualTo("B"); } - /// - /// Verifies that two-property WhenChanging emits initial values. - /// + /// Verifies that two-property WhenChanging emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task TwoProperties_EmitsInitialTuple() @@ -139,9 +118,7 @@ public async Task TwoProperties_EmitsInitialTuple() await Assert.That(values[0].property2).IsEqualTo(TwoPropIntValue); } - /// - /// Verifies that three-property WhenChanging emits initial values. - /// + /// Verifies that three-property WhenChanging emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task ThreeProperties_EmitsInitialValues() @@ -158,9 +135,7 @@ public async Task ThreeProperties_EmitsInitialValues() await Assert.That(values[0].property3).IsEqualTo(ThreePropDoubleValue); } - /// - /// Verifies that four-property WhenChanging emits initial values. - /// + /// Verifies that four-property WhenChanging emits initial values. /// A task representing the asynchronous test operation. [Test] public async Task FourProperties_EmitsInitialValues() @@ -178,9 +153,7 @@ public async Task FourProperties_EmitsInitialValues() await Assert.That(values[0].property4).IsTrue(); } - /// - /// Verifies that disposing the subscription stops listening for changes. - /// + /// Verifies that disposing the subscription stops listening for changes. /// A task representing the asynchronous test operation. [Test] public async Task Disposal_StopsListening() diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/AssemblySetup.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/AssemblySetup.cs index 8685f6d..2ca09c1 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/AssemblySetup.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/AssemblySetup.cs @@ -6,19 +6,18 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests; -/// -/// Assembly-level setup for source generator tests. -/// +/// Assembly-level setup for source generator tests. public static class AssemblySetup { - /// - /// Initializes the source generators. - /// + /// Initializes the source generators. [Before(Assembly)] public static void Init() { VerifySourceGenerators.Initialize(); VerifierSettings.UseSplitModeForUniqueDirectory(); - ////VerifierSettings.AutoVerify(); + + // To accept new or changed snapshots, uncomment the AutoVerify call below, run the suite, + // then comment it out again and re-run to confirm the snapshots pass on their own. + ////VerifierSettings.AutoVerify() } } diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.BasicNoParam#BindCommandDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.BasicNoParam#BindCommandDispatch.g.verified.cs index b4ce1f9..25ac151 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.BasicNoParam#BindCommandDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.BasicNoParam#BindCommandDispatch.g.verified.cs @@ -30,13 +30,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (propertyNameExpression == "x => x.Save" && controlNameExpression == "x => x.SaveButton") { - return __BindCommand_7FFFF69B2C59E18F(view, viewModel); + return __BindCommand_7FFFF69B2C59DF23(view, viewModel); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindCommand_7FFFF69B2C59E18F( + private static global::System.IDisposable __BindCommand_7FFFF69B2C59DF23( global::SharedScenarios.BindCommand.BasicNoParam.MyView view, global::SharedScenarios.BindCommand.BasicNoParam.MyViewModel viewModel) { diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.CFPFallback#BindCommandDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.CFPFallback#BindCommandDispatch.g.verified.cs index 047d9bf..363ff34 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.CFPFallback#BindCommandDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.CFPFallback#BindCommandDispatch.g.verified.cs @@ -22,16 +22,16 @@ internal static partial class __ReactiveUIGeneratedBindings [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (callerLineNumber == 93 + if (callerLineNumber == 73 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) { - return __BindCommand_7FFFF69B2C59E18F(view, viewModel); + return __BindCommand_7FFFF69B2C59DF23(view, viewModel); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindCommand_7FFFF69B2C59E18F( + private static global::System.IDisposable __BindCommand_7FFFF69B2C59DF23( global::SharedScenarios.BindCommand.BasicNoParam.MyView view, global::SharedScenarios.BindCommand.BasicNoParam.MyViewModel viewModel) { diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.CFPFallback_ExpressionParam#BindCommandDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.CFPFallback_ExpressionParam#BindCommandDispatch.g.verified.cs index 416c453..0a2c37f 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.CFPFallback_ExpressionParam#BindCommandDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.CFPFallback_ExpressionParam#BindCommandDispatch.g.verified.cs @@ -23,16 +23,16 @@ internal static partial class __ReactiveUIGeneratedBindings [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (callerLineNumber == 116 + if (callerLineNumber == 92 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) { - return __BindCommand_7FFFEA737737D49B(view, viewModel); + return __BindCommand_7FFFEA737737D1B3(view, viewModel); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindCommand_7FFFEA737737D49B( + private static global::System.IDisposable __BindCommand_7FFFEA737737D1B3( global::SharedScenarios.BindCommand.ExpressionParam.MyView view, global::SharedScenarios.BindCommand.ExpressionParam.MyViewModel viewModel) { diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.CFPFallback_ObservableParam#BindCommandDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.CFPFallback_ObservableParam#BindCommandDispatch.g.verified.cs index a114e7a..7b842e0 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.CFPFallback_ObservableParam#BindCommandDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.CFPFallback_ObservableParam#BindCommandDispatch.g.verified.cs @@ -23,16 +23,16 @@ internal static partial class __ReactiveUIGeneratedBindings [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (callerLineNumber == 94 + if (callerLineNumber == 74 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) { - return __BindCommand_00000F3AD26C99BA(view, viewModel, withParameter); + return __BindCommand_00000F3AD26C974E(view, viewModel, withParameter); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindCommand_00000F3AD26C99BA( + private static global::System.IDisposable __BindCommand_00000F3AD26C974E( global::SharedScenarios.BindCommand.ObservableParam.MyView view, global::SharedScenarios.BindCommand.ObservableParam.MyViewModel viewModel, global::System.IObservable withParameter) { diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.CommandProperty#BindCommandDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.CommandProperty#BindCommandDispatch.g.verified.cs index f5c5e2c..74bc5dc 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.CommandProperty#BindCommandDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.CommandProperty#BindCommandDispatch.g.verified.cs @@ -30,13 +30,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (propertyNameExpression == "x => x.Save" && controlNameExpression == "x => x.SaveButton") { - return __BindCommand_00000A6C4A2CDEE0(view, viewModel); + return __BindCommand_00000A6C4A2CDD6C(view, viewModel); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindCommand_00000A6C4A2CDEE0( + private static global::System.IDisposable __BindCommand_00000A6C4A2CDD6C( global::SharedScenarios.BindCommand.CommandProperty.MyView view, global::SharedScenarios.BindCommand.CommandProperty.MyViewModel viewModel) { diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.CommandPropertyExprParam#BindCommandDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.CommandPropertyExprParam#BindCommandDispatch.g.verified.cs index a0461fb..cdeb73f 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.CommandPropertyExprParam#BindCommandDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.CommandPropertyExprParam#BindCommandDispatch.g.verified.cs @@ -32,13 +32,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (propertyNameExpression == "x => x.Save" && controlNameExpression == "x => x.SaveButton") { - return __BindCommand_00000CE640707129(view, viewModel); + return __BindCommand_00000CE640706F39(view, viewModel); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindCommand_00000CE640707129( + private static global::System.IDisposable __BindCommand_00000CE640706F39( global::SharedScenarios.BindCommand.CommandPropertyExprParam.MyView view, global::SharedScenarios.BindCommand.CommandPropertyExprParam.MyViewModel viewModel) { diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.CommandPropertyObsParam#BindCommandDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.CommandPropertyObsParam#BindCommandDispatch.g.verified.cs index 9627389..1b79b4a 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.CommandPropertyObsParam#BindCommandDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.CommandPropertyObsParam#BindCommandDispatch.g.verified.cs @@ -31,13 +31,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (propertyNameExpression == "x => x.Save" && controlNameExpression == "x => x.SaveButton") { - return __BindCommand_000025BD0B2B0284(view, viewModel, withParameter); + return __BindCommand_000025BD0B2B0110(view, viewModel, withParameter); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindCommand_000025BD0B2B0284( + private static global::System.IDisposable __BindCommand_000025BD0B2B0110( global::SharedScenarios.BindCommand.CommandPropertyObsParam.MyView view, global::SharedScenarios.BindCommand.CommandPropertyObsParam.MyViewModel viewModel, global::System.IObservable withParameter) { diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.CustomEvent#BindCommandDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.CustomEvent#BindCommandDispatch.g.verified.cs index 6a9b3a7..ffffea7 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.CustomEvent#BindCommandDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.CustomEvent#BindCommandDispatch.g.verified.cs @@ -30,13 +30,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (propertyNameExpression == "x => x.Save" && controlNameExpression == "x => x.SaveButton") { - return __BindCommand_000010E3246572E8(view, viewModel); + return __BindCommand_000010E32465707C(view, viewModel); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindCommand_000010E3246572E8( + private static global::System.IDisposable __BindCommand_000010E32465707C( global::SharedScenarios.BindCommand.CustomEvent.MyView view, global::SharedScenarios.BindCommand.CustomEvent.MyViewModel viewModel) { diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.DeepCommandPath#BindCommandDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.DeepCommandPath#BindCommandDispatch.g.verified.cs index 994857e..c0a4084 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.DeepCommandPath#BindCommandDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.DeepCommandPath#BindCommandDispatch.g.verified.cs @@ -30,13 +30,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (propertyNameExpression == "x => x.Child!.SaveCommand" && controlNameExpression == "x => x.SaveButton") { - return __BindCommand_7FFFEA7C178C383A(view, viewModel); + return __BindCommand_7FFFEA7C178C3514(view, viewModel); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindCommand_7FFFEA7C178C383A( + private static global::System.IDisposable __BindCommand_7FFFEA7C178C3514( global::SharedScenarios.BindCommand.DeepCommandPath.MyView view, global::SharedScenarios.BindCommand.DeepCommandPath.MyViewModel viewModel) { diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.EventEnabled#BindCommandDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.EventEnabled#BindCommandDispatch.g.verified.cs index d7507cf..a92e0ce 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.EventEnabled#BindCommandDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.EventEnabled#BindCommandDispatch.g.verified.cs @@ -30,13 +30,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (propertyNameExpression == "x => x.Save" && controlNameExpression == "x => x.SaveButton") { - return __BindCommand_0000372503979CEF(view, viewModel); + return __BindCommand_0000372503979B7B(view, viewModel); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindCommand_0000372503979CEF( + private static global::System.IDisposable __BindCommand_0000372503979B7B( global::SharedScenarios.BindCommand.EventEnabled.MyView view, global::SharedScenarios.BindCommand.EventEnabled.MyViewModel viewModel) { diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.EventEnabledExprParam#BindCommandDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.EventEnabledExprParam#BindCommandDispatch.g.verified.cs index 0d7ed77..5b2649f 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.EventEnabledExprParam#BindCommandDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.EventEnabledExprParam#BindCommandDispatch.g.verified.cs @@ -32,13 +32,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (propertyNameExpression == "x => x.Save" && controlNameExpression == "x => x.SaveButton") { - return __BindCommand_00001A92FB3E1C2A(view, viewModel); + return __BindCommand_00001A92FB3E1A3A(view, viewModel); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindCommand_00001A92FB3E1C2A( + private static global::System.IDisposable __BindCommand_00001A92FB3E1A3A( global::SharedScenarios.BindCommand.EventEnabledExprParam.MyView view, global::SharedScenarios.BindCommand.EventEnabledExprParam.MyViewModel viewModel) { diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.EventEnabledObsParam#BindCommandDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.EventEnabledObsParam#BindCommandDispatch.g.verified.cs index 67814f4..fdecfc3 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.EventEnabledObsParam#BindCommandDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.EventEnabledObsParam#BindCommandDispatch.g.verified.cs @@ -31,13 +31,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (propertyNameExpression == "x => x.Save" && controlNameExpression == "x => x.SaveButton") { - return __BindCommand_00001723A43D0499(view, viewModel, withParameter); + return __BindCommand_00001723A43D0325(view, viewModel, withParameter); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindCommand_00001723A43D0499( + private static global::System.IDisposable __BindCommand_00001723A43D0325( global::SharedScenarios.BindCommand.EventEnabledObsParam.MyView view, global::SharedScenarios.BindCommand.EventEnabledObsParam.MyViewModel viewModel, global::System.IObservable withParameter) { diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.ExpressionParam#BindCommandDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.ExpressionParam#BindCommandDispatch.g.verified.cs index c96ddf9..85c2db2 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.ExpressionParam#BindCommandDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.ExpressionParam#BindCommandDispatch.g.verified.cs @@ -32,13 +32,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (propertyNameExpression == "x => x.Save" && controlNameExpression == "x => x.SaveButton") { - return __BindCommand_7FFFEA737737D49B(view, viewModel); + return __BindCommand_7FFFEA737737D1B3(view, viewModel); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindCommand_7FFFEA737737D49B( + private static global::System.IDisposable __BindCommand_7FFFEA737737D1B3( global::SharedScenarios.BindCommand.ExpressionParam.MyView view, global::SharedScenarios.BindCommand.ExpressionParam.MyViewModel viewModel) { diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.NoEvent#BindCommandDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.NoEvent#BindCommandDispatch.g.verified.cs index 7c8989c..1aa5f39 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.NoEvent#BindCommandDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.NoEvent#BindCommandDispatch.g.verified.cs @@ -30,13 +30,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (propertyNameExpression == "x => x.Save" && controlNameExpression == "x => x.Label") { - return __BindCommand_000006F07B8E72DE(view, viewModel); + return __BindCommand_000006F07B8E70B0(view, viewModel); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindCommand_000006F07B8E72DE( + private static global::System.IDisposable __BindCommand_000006F07B8E70B0( global::SharedScenarios.BindCommand.NoEvent.MyView view, global::SharedScenarios.BindCommand.NoEvent.MyViewModel viewModel) { diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.ObservableParam#BindCommandDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.ObservableParam#BindCommandDispatch.g.verified.cs index 338bd29..5619bf0 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.ObservableParam#BindCommandDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BCG.ObservableParam#BindCommandDispatch.g.verified.cs @@ -31,13 +31,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (propertyNameExpression == "x => x.Save" && controlNameExpression == "x => x.SaveButton") { - return __BindCommand_00000F3AD26C99BA(view, viewModel, withParameter); + return __BindCommand_00000F3AD26C974E(view, viewModel, withParameter); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindCommand_00000F3AD26C99BA( + private static global::System.IDisposable __BindCommand_00000F3AD26C974E( global::SharedScenarios.BindCommand.ObservableParam.MyView view, global::SharedScenarios.BindCommand.ObservableParam.MyViewModel viewModel, global::System.IObservable withParameter) { diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BG.2STB_GEI#BindDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BG.2STB_GEI#BindDispatch.g.verified.cs index 19e4e73..714a430 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BG.2STB_GEI#BindDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BG.2STB_GEI#BindDispatch.g.verified.cs @@ -16,28 +16,28 @@ internal static partial class __ReactiveUIGeneratedBindings public static global::ReactiveUI.Binding.IReactiveBinding Bind( this global::SharedScenarios.Bind.TwoSameTypeBindings.MyView view, global::SharedScenarios.Bind.TwoSameTypeBindings.MyViewModel viewModel, - global::System.Linq.Expressions.Expression> vmProperty, + global::System.Linq.Expressions.Expression> viewModelProperty, global::System.Linq.Expressions.Expression> viewProperty, - [global::System.Runtime.CompilerServices.CallerArgumentExpression("vmProperty")] string vmPropertyExpression = "", + [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewModelProperty")] string viewModelPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewProperty")] string viewPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (vmPropertyExpression == "x => x.FirstName" + if (viewModelPropertyExpression == "x => x.FirstName" && viewPropertyExpression == "x => x.FirstNameText") { - return __Bind_7FFFE38A2E1A46F6(viewModel, view); + return __Bind_7FFFE38A2E1A448A(viewModel, view); } - else if (vmPropertyExpression == "x => x.LastName" + else if (viewModelPropertyExpression == "x => x.LastName" && viewPropertyExpression == "x => x.LastNameText") { - return __Bind_7FFFE389FC4EED6D(viewModel, view); + return __Bind_7FFFE389FC4EEB01(viewModel, view); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::ReactiveUI.Binding.IReactiveBinding __Bind_7FFFE38A2E1A46F6(global::SharedScenarios.Bind.TwoSameTypeBindings.MyViewModel viewModel, global::SharedScenarios.Bind.TwoSameTypeBindings.MyView view) + private static global::ReactiveUI.Binding.IReactiveBinding __Bind_7FFFE38A2E1A448A(global::SharedScenarios.Bind.TwoSameTypeBindings.MyViewModel viewModel, global::SharedScenarios.Bind.TwoSameTypeBindings.MyView view) { // Bind: FirstName <-> FirstNameText var vmObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( @@ -75,7 +75,7 @@ internal static partial class __ReactiveUIGeneratedBindings disposable); } - private static global::ReactiveUI.Binding.IReactiveBinding __Bind_7FFFE389FC4EED6D(global::SharedScenarios.Bind.TwoSameTypeBindings.MyViewModel viewModel, global::SharedScenarios.Bind.TwoSameTypeBindings.MyView view) + private static global::ReactiveUI.Binding.IReactiveBinding __Bind_7FFFE389FC4EEB01(global::SharedScenarios.Bind.TwoSameTypeBindings.MyViewModel viewModel, global::SharedScenarios.Bind.TwoSameTypeBindings.MyView view) { // Bind: LastName <-> LastNameText var vmObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BG.MB#BindDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BG.MB#BindDispatch.g.verified.cs index b208c79..c49f91e 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BG.MB#BindDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BG.MB#BindDispatch.g.verified.cs @@ -16,23 +16,23 @@ internal static partial class __ReactiveUIGeneratedBindings public static global::ReactiveUI.Binding.IReactiveBinding Bind( this global::SharedScenarios.Bind.MultipleBindings.MyView view, global::SharedScenarios.Bind.MultipleBindings.MyViewModel viewModel, - global::System.Linq.Expressions.Expression> vmProperty, + global::System.Linq.Expressions.Expression> viewModelProperty, global::System.Linq.Expressions.Expression> viewProperty, - [global::System.Runtime.CompilerServices.CallerArgumentExpression("vmProperty")] string vmPropertyExpression = "", + [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewModelProperty")] string viewModelPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewProperty")] string viewPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (vmPropertyExpression == "x => x.Name" + if (viewModelPropertyExpression == "x => x.Name" && viewPropertyExpression == "x => x.NameText") { - return __Bind_7FFFFC09455D2E5A(viewModel, view); + return __Bind_7FFFFC09455D2B72(viewModel, view); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::ReactiveUI.Binding.IReactiveBinding __Bind_7FFFFC09455D2E5A(global::SharedScenarios.Bind.MultipleBindings.MyViewModel viewModel, global::SharedScenarios.Bind.MultipleBindings.MyView view) + private static global::ReactiveUI.Binding.IReactiveBinding __Bind_7FFFFC09455D2B72(global::SharedScenarios.Bind.MultipleBindings.MyViewModel viewModel, global::SharedScenarios.Bind.MultipleBindings.MyView view) { // Bind: Name <-> NameText var vmObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( @@ -77,23 +77,23 @@ internal static partial class __ReactiveUIGeneratedBindings public static global::ReactiveUI.Binding.IReactiveBinding Bind( this global::SharedScenarios.Bind.MultipleBindings.MyView view, global::SharedScenarios.Bind.MultipleBindings.MyViewModel viewModel, - global::System.Linq.Expressions.Expression> vmProperty, + global::System.Linq.Expressions.Expression> viewModelProperty, global::System.Linq.Expressions.Expression> viewProperty, - [global::System.Runtime.CompilerServices.CallerArgumentExpression("vmProperty")] string vmPropertyExpression = "", + [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewModelProperty")] string viewModelPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewProperty")] string viewPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (vmPropertyExpression == "x => x.Age" + if (viewModelPropertyExpression == "x => x.Age" && viewPropertyExpression == "x => x.AgeText") { - return __Bind_7FFFFC08E70C4319(viewModel, view); + return __Bind_7FFFFC08E70C4031(viewModel, view); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::ReactiveUI.Binding.IReactiveBinding __Bind_7FFFFC08E70C4319(global::SharedScenarios.Bind.MultipleBindings.MyViewModel viewModel, global::SharedScenarios.Bind.MultipleBindings.MyView view) + private static global::ReactiveUI.Binding.IReactiveBinding __Bind_7FFFFC08E70C4031(global::SharedScenarios.Bind.MultipleBindings.MyViewModel viewModel, global::SharedScenarios.Bind.MultipleBindings.MyView view) { // Bind: Age <-> AgeText var vmObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BG.SP_S2S#BindDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BG.SP_S2S#BindDispatch.g.verified.cs index db47fdd..4ed8240 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BG.SP_S2S#BindDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BG.SP_S2S#BindDispatch.g.verified.cs @@ -16,23 +16,23 @@ internal static partial class __ReactiveUIGeneratedBindings public static global::ReactiveUI.Binding.IReactiveBinding Bind( this global::SharedScenarios.Bind.SinglePropertyStringToString.MyView view, global::SharedScenarios.Bind.SinglePropertyStringToString.MyViewModel viewModel, - global::System.Linq.Expressions.Expression> vmProperty, + global::System.Linq.Expressions.Expression> viewModelProperty, global::System.Linq.Expressions.Expression> viewProperty, - [global::System.Runtime.CompilerServices.CallerArgumentExpression("vmProperty")] string vmPropertyExpression = "", + [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewModelProperty")] string viewModelPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewProperty")] string viewPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (vmPropertyExpression == "x => x.Name" + if (viewModelPropertyExpression == "x => x.Name" && viewPropertyExpression == "x => x.NameText") { - return __Bind_000011908961B7FB(viewModel, view); + return __Bind_000011908961B60B(viewModel, view); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::ReactiveUI.Binding.IReactiveBinding __Bind_000011908961B7FB(global::SharedScenarios.Bind.SinglePropertyStringToString.MyViewModel viewModel, global::SharedScenarios.Bind.SinglePropertyStringToString.MyView view) + private static global::ReactiveUI.Binding.IReactiveBinding __Bind_000011908961B60B(global::SharedScenarios.Bind.SinglePropertyStringToString.MyViewModel viewModel, global::SharedScenarios.Bind.SinglePropertyStringToString.MyView view) { // Bind: Name <-> NameText var vmObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BG.SP_S2S_CFP#BindDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BG.SP_S2S_CFP#BindDispatch.g.verified.cs index 211afaa..7963208 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BG.SP_S2S_CFP#BindDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BG.SP_S2S_CFP#BindDispatch.g.verified.cs @@ -16,21 +16,21 @@ internal static partial class __ReactiveUIGeneratedBindings public static global::ReactiveUI.Binding.IReactiveBinding Bind( this global::SharedScenarios.Bind.SinglePropertyStringToString.MyView view, global::SharedScenarios.Bind.SinglePropertyStringToString.MyViewModel viewModel, - global::System.Linq.Expressions.Expression> vmProperty, + global::System.Linq.Expressions.Expression> viewModelProperty, global::System.Linq.Expressions.Expression> viewProperty, [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (callerLineNumber == 90 + if (callerLineNumber == 74 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) { - return __Bind_000011908961B7FB(viewModel, view); + return __Bind_000011908961B60B(viewModel, view); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::ReactiveUI.Binding.IReactiveBinding __Bind_000011908961B7FB(global::SharedScenarios.Bind.SinglePropertyStringToString.MyViewModel viewModel, global::SharedScenarios.Bind.SinglePropertyStringToString.MyView view) + private static global::ReactiveUI.Binding.IReactiveBinding __Bind_000011908961B60B(global::SharedScenarios.Bind.SinglePropertyStringToString.MyViewModel viewModel, global::SharedScenarios.Bind.SinglePropertyStringToString.MyView view) { // Bind: Name <-> NameText var vmObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BG.SP_WC#BindDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BG.SP_WC#BindDispatch.g.verified.cs index f00174e..a82aaf5 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BG.SP_WC#BindDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BG.SP_WC#BindDispatch.g.verified.cs @@ -16,25 +16,25 @@ internal static partial class __ReactiveUIGeneratedBindings public static global::ReactiveUI.Binding.IReactiveBinding Bind( this global::SharedScenarios.Bind.SinglePropertyWithConverters.MyView view, global::SharedScenarios.Bind.SinglePropertyWithConverters.MyViewModel viewModel, - global::System.Linq.Expressions.Expression> vmProperty, + global::System.Linq.Expressions.Expression> viewModelProperty, global::System.Linq.Expressions.Expression> viewProperty, - global::System.Func vmToViewConverter, - global::System.Func viewToVmConverter, - [global::System.Runtime.CompilerServices.CallerArgumentExpression("vmProperty")] string vmPropertyExpression = "", + global::System.Func viewModelToViewConverter, + global::System.Func viewToViewModelConverter, + [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewModelProperty")] string viewModelPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewProperty")] string viewPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (vmPropertyExpression == "x => x.Count" + if (viewModelPropertyExpression == "x => x.Count" && viewPropertyExpression == "x => x.CountText") { - return __Bind_0000102A67853E4B(viewModel, view, vmToViewConverter, viewToVmConverter); + return __Bind_0000102A67853C5B(viewModel, view, viewModelToViewConverter, viewToViewModelConverter); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::ReactiveUI.Binding.IReactiveBinding __Bind_0000102A67853E4B(global::SharedScenarios.Bind.SinglePropertyWithConverters.MyViewModel viewModel, global::SharedScenarios.Bind.SinglePropertyWithConverters.MyView view, global::System.Func vmToViewConverter, global::System.Func viewToVmConverter) + private static global::ReactiveUI.Binding.IReactiveBinding __Bind_0000102A67853C5B(global::SharedScenarios.Bind.SinglePropertyWithConverters.MyViewModel viewModel, global::SharedScenarios.Bind.SinglePropertyWithConverters.MyView view, global::System.Func viewModelToViewConverter, global::System.Func viewToViewModelConverter) { // Bind: Count <-> CountText (with conversion) var vmObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( @@ -47,8 +47,8 @@ internal static partial class __ReactiveUIGeneratedBindings "CountText", (global::System.ComponentModel.INotifyPropertyChanged __o) => ((global::SharedScenarios.Bind.SinglePropertyWithConverters.MyView)__o).CountText, true); - var vmBind = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select(vmObs, vmToViewConverter); - var viewBind = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select(viewObs, viewToVmConverter); + var vmBind = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select(vmObs, viewModelToViewConverter); + var viewBind = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select(viewObs, viewToViewModelConverter); var d1 = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Subscribe(vmBind, value => { diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BG.SP_WCSched#BindDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BG.SP_WCSched#BindDispatch.g.verified.cs index 82517aa..7225746 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BG.SP_WCSched#BindDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BG.SP_WCSched#BindDispatch.g.verified.cs @@ -16,26 +16,26 @@ internal static partial class __ReactiveUIGeneratedBindings public static global::ReactiveUI.Binding.IReactiveBinding Bind( this global::SharedScenarios.Bind.SinglePropertyWithConvertersAndScheduler.MyView view, global::SharedScenarios.Bind.SinglePropertyWithConvertersAndScheduler.MyViewModel viewModel, - global::System.Linq.Expressions.Expression> vmProperty, + global::System.Linq.Expressions.Expression> viewModelProperty, global::System.Linq.Expressions.Expression> viewProperty, - global::System.Func vmToViewConverter, - global::System.Func viewToVmConverter, + global::System.Func viewModelToViewConverter, + global::System.Func viewToViewModelConverter, global::System.Reactive.Concurrency.IScheduler scheduler, - [global::System.Runtime.CompilerServices.CallerArgumentExpression("vmProperty")] string vmPropertyExpression = "", + [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewModelProperty")] string viewModelPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewProperty")] string viewPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (vmPropertyExpression == "x => x.Count" + if (viewModelPropertyExpression == "x => x.Count" && viewPropertyExpression == "x => x.CountText") { - return __Bind_7FFFD53F494406F0(viewModel, view, vmToViewConverter, viewToVmConverter, scheduler); + return __Bind_7FFFD53F49440500(viewModel, view, viewModelToViewConverter, viewToViewModelConverter, scheduler); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::ReactiveUI.Binding.IReactiveBinding __Bind_7FFFD53F494406F0(global::SharedScenarios.Bind.SinglePropertyWithConvertersAndScheduler.MyViewModel viewModel, global::SharedScenarios.Bind.SinglePropertyWithConvertersAndScheduler.MyView view, global::System.Func vmToViewConverter, global::System.Func viewToVmConverter, global::System.Reactive.Concurrency.IScheduler scheduler) + private static global::ReactiveUI.Binding.IReactiveBinding __Bind_7FFFD53F49440500(global::SharedScenarios.Bind.SinglePropertyWithConvertersAndScheduler.MyViewModel viewModel, global::SharedScenarios.Bind.SinglePropertyWithConvertersAndScheduler.MyView view, global::System.Func viewModelToViewConverter, global::System.Func viewToViewModelConverter, global::System.Reactive.Concurrency.IScheduler scheduler) { // Bind: Count <-> CountText (with conversion) (with scheduler) var vmObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( @@ -48,8 +48,8 @@ internal static partial class __ReactiveUIGeneratedBindings "CountText", (global::System.ComponentModel.INotifyPropertyChanged __o) => ((global::SharedScenarios.Bind.SinglePropertyWithConvertersAndScheduler.MyView)__o).CountText, true); - var __vmSelected = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select(vmObs, vmToViewConverter); - var __viewSelected = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select(viewObs, viewToVmConverter); + var __vmSelected = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select(vmObs, viewModelToViewConverter); + var __viewSelected = global::ReactiveUI.Binding.Observables.RxBindingExtensions.Select(viewObs, viewToViewModelConverter); var vmBind = new global::ReactiveUI.Binding.Reactive.ObserveOnObservable(__vmSelected, scheduler); var viewBind = new global::ReactiveUI.Binding.Reactive.ObserveOnObservable(__viewSelected, scheduler); diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.CFPFallback#BindInteractionDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.CFPFallback#BindInteractionDispatch.g.verified.cs index c823744..2f1c84a 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.CFPFallback#BindInteractionDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.CFPFallback#BindInteractionDispatch.g.verified.cs @@ -21,16 +21,16 @@ internal static partial class __ReactiveUIGeneratedBindings [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (callerLineNumber == 72 + if (callerLineNumber == 60 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) { - return __BindInteraction_000025C4B6C6801D(viewModel, handler); + return __BindInteraction_000025C4B6C67EA9(viewModel, handler); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindInteraction_000025C4B6C6801D( + private static global::System.IDisposable __BindInteraction_000025C4B6C67EA9( global::SharedScenarios.BindInteraction.TaskHandler.MyViewModel viewModel, global::System.Func, global::System.Threading.Tasks.Task> handler) { diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.CFPFallback_DeepPropertyPath#BindInteractionDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.CFPFallback_DeepPropertyPath#BindInteractionDispatch.g.verified.cs index 5d709e2..1a7469d 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.CFPFallback_DeepPropertyPath#BindInteractionDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.CFPFallback_DeepPropertyPath#BindInteractionDispatch.g.verified.cs @@ -21,16 +21,16 @@ internal static partial class __ReactiveUIGeneratedBindings [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (callerLineNumber == 104 + if (callerLineNumber == 86 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) { - return __BindInteraction_7FFFEF09AD5AF4FB(viewModel, handler); + return __BindInteraction_7FFFEF09AD5AF2CD(viewModel, handler); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindInteraction_7FFFEF09AD5AF4FB( + private static global::System.IDisposable __BindInteraction_7FFFEF09AD5AF2CD( global::SharedScenarios.BindInteraction.DeepPropertyPath.MyViewModel viewModel, global::System.Func, global::System.Threading.Tasks.Task> handler) { diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.CFPFallback_NonINPCViewModel#BindInteractionDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.CFPFallback_NonINPCViewModel#BindInteractionDispatch.g.verified.cs index 37b1cab..e3e587c 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.CFPFallback_NonINPCViewModel#BindInteractionDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.CFPFallback_NonINPCViewModel#BindInteractionDispatch.g.verified.cs @@ -21,16 +21,16 @@ internal static partial class __ReactiveUIGeneratedBindings [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (callerLineNumber == 52 + if (callerLineNumber == 44 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) { - return __BindInteraction_7FFFCBE90BBDA3D5(viewModel, handler); + return __BindInteraction_7FFFCBE90BBDA2DD(viewModel, handler); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindInteraction_7FFFCBE90BBDA3D5( + private static global::System.IDisposable __BindInteraction_7FFFCBE90BBDA2DD( global::SharedScenarios.BindInteraction.NonINPCViewModel.MyViewModel viewModel, global::System.Func, global::System.Threading.Tasks.Task> handler) { diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.CFPFallback_ObservableHandler#BindInteractionDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.CFPFallback_ObservableHandler#BindInteractionDispatch.g.verified.cs index f7b2aab..26bbdec 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.CFPFallback_ObservableHandler#BindInteractionDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.CFPFallback_ObservableHandler#BindInteractionDispatch.g.verified.cs @@ -21,16 +21,16 @@ internal static partial class __ReactiveUIGeneratedBindings [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (callerLineNumber == 71 + if (callerLineNumber == 59 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) { - return __BindInteraction_7FFFDDE16443AE6A(viewModel, handler); + return __BindInteraction_7FFFDDE16443ACF6(viewModel, handler); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindInteraction_7FFFDDE16443AE6A( + private static global::System.IDisposable __BindInteraction_7FFFDDE16443ACF6( global::SharedScenarios.BindInteraction.ObservableHandler.MyViewModel viewModel, global::System.Func, global::System.IObservable> handler) { diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.DeepPropertyPath#BindInteractionDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.DeepPropertyPath#BindInteractionDispatch.g.verified.cs index a336e41..01084ae 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.DeepPropertyPath#BindInteractionDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.DeepPropertyPath#BindInteractionDispatch.g.verified.cs @@ -26,13 +26,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (propertyNameExpression == "x => x.Child!.Confirm") { - return __BindInteraction_7FFFEF09AD5AF4FB(viewModel, handler); + return __BindInteraction_7FFFEF09AD5AF2CD(viewModel, handler); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindInteraction_7FFFEF09AD5AF4FB( + private static global::System.IDisposable __BindInteraction_7FFFEF09AD5AF2CD( global::SharedScenarios.BindInteraction.DeepPropertyPath.MyViewModel viewModel, global::System.Func, global::System.Threading.Tasks.Task> handler) { diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.NonINPCViewModel#BindInteractionDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.NonINPCViewModel#BindInteractionDispatch.g.verified.cs index a01bf3f..d1daec9 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.NonINPCViewModel#BindInteractionDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.NonINPCViewModel#BindInteractionDispatch.g.verified.cs @@ -26,13 +26,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (propertyNameExpression == "x => x.Confirm") { - return __BindInteraction_7FFFCBE90BBDA3D5(viewModel, handler); + return __BindInteraction_7FFFCBE90BBDA2DD(viewModel, handler); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindInteraction_7FFFCBE90BBDA3D5( + private static global::System.IDisposable __BindInteraction_7FFFCBE90BBDA2DD( global::SharedScenarios.BindInteraction.NonINPCViewModel.MyViewModel viewModel, global::System.Func, global::System.Threading.Tasks.Task> handler) { diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.ObservableHandler#BindInteractionDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.ObservableHandler#BindInteractionDispatch.g.verified.cs index 5683bea..226ac77 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.ObservableHandler#BindInteractionDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.ObservableHandler#BindInteractionDispatch.g.verified.cs @@ -26,13 +26,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (propertyNameExpression == "x => x.Confirm") { - return __BindInteraction_7FFFDDE16443AE6A(viewModel, handler); + return __BindInteraction_7FFFDDE16443ACF6(viewModel, handler); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindInteraction_7FFFDDE16443AE6A( + private static global::System.IDisposable __BindInteraction_7FFFDDE16443ACF6( global::SharedScenarios.BindInteraction.ObservableHandler.MyViewModel viewModel, global::System.Func, global::System.IObservable> handler) { diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.TaskHandler#BindInteractionDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.TaskHandler#BindInteractionDispatch.g.verified.cs index d112193..698794b 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.TaskHandler#BindInteractionDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BIG.TaskHandler#BindInteractionDispatch.g.verified.cs @@ -26,13 +26,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (propertyNameExpression == "x => x.Confirm") { - return __BindInteraction_000025C4B6C6801D(viewModel, handler); + return __BindInteraction_000025C4B6C67EA9(viewModel, handler); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindInteraction_000025C4B6C6801D( + private static global::System.IDisposable __BindInteraction_000025C4B6C67EA9( global::SharedScenarios.BindInteraction.TaskHandler.MyViewModel viewModel, global::System.Func, global::System.Threading.Tasks.Task> handler) { diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.MB#BindOneWayDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.MB#BindOneWayDispatch.g.verified.cs index eaf3e0d..07ba7b0 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.MB#BindOneWayDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.MB#BindOneWayDispatch.g.verified.cs @@ -29,13 +29,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (sourcePropertyExpression == "x => x.Name" && targetPropertyExpression == "x => x.NameText") { - return __BindOneWay_0000160B29D0A06A(source, target); + return __BindOneWay_0000160B29D09D82(source, target); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindOneWay_0000160B29D0A06A(global::SharedScenarios.BindOneWay.MultipleBindings.MyViewModel source, global::SharedScenarios.BindOneWay.MultipleBindings.MyView target) + private static global::System.IDisposable __BindOneWay_0000160B29D09D82(global::SharedScenarios.BindOneWay.MultipleBindings.MyViewModel source, global::SharedScenarios.BindOneWay.MultipleBindings.MyView target) { // BindOneWay: Name -> NameText var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( @@ -70,13 +70,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (sourcePropertyExpression == "x => x.Age" && targetPropertyExpression == "x => x.AgeDisplay") { - return __BindOneWay_0000160B1B58B4C9(source, target); + return __BindOneWay_0000160B1B58B1E1(source, target); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindOneWay_0000160B1B58B4C9(global::SharedScenarios.BindOneWay.MultipleBindings.MyViewModel source, global::SharedScenarios.BindOneWay.MultipleBindings.MyView target) + private static global::System.IDisposable __BindOneWay_0000160B1B58B1E1(global::SharedScenarios.BindOneWay.MultipleBindings.MyViewModel source, global::SharedScenarios.BindOneWay.MultipleBindings.MyView target) { // BindOneWay: Age -> AgeDisplay var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.MSTB#BindOneWayDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.MSTB#BindOneWayDispatch.g.verified.cs index ded3887..2481e60 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.MSTB#BindOneWayDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.MSTB#BindOneWayDispatch.g.verified.cs @@ -29,18 +29,18 @@ internal static partial class __ReactiveUIGeneratedBindings if (sourcePropertyExpression == "x => x.FirstName" && targetPropertyExpression == "x => x.FirstNameText") { - return __BindOneWay_0000177DD18BA19C(source, target); + return __BindOneWay_0000177DD18B9EB4(source, target); } else if (sourcePropertyExpression == "x => x.LastName" && targetPropertyExpression == "x => x.LastNameText") { - return __BindOneWay_0000177D9FC04813(source, target); + return __BindOneWay_0000177D9FC0452B(source, target); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindOneWay_0000177DD18BA19C(global::SharedScenarios.BindOneWay.MultipleSameTypeBindings.MyViewModel source, global::SharedScenarios.BindOneWay.MultipleSameTypeBindings.MyView target) + private static global::System.IDisposable __BindOneWay_0000177DD18B9EB4(global::SharedScenarios.BindOneWay.MultipleSameTypeBindings.MyViewModel source, global::SharedScenarios.BindOneWay.MultipleSameTypeBindings.MyView target) { // BindOneWay: FirstName -> FirstNameText var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( @@ -55,7 +55,7 @@ internal static partial class __ReactiveUIGeneratedBindings }); } - private static global::System.IDisposable __BindOneWay_0000177D9FC04813(global::SharedScenarios.BindOneWay.MultipleSameTypeBindings.MyViewModel source, global::SharedScenarios.BindOneWay.MultipleSameTypeBindings.MyView target) + private static global::System.IDisposable __BindOneWay_0000177D9FC0452B(global::SharedScenarios.BindOneWay.MultipleSameTypeBindings.MyViewModel source, global::SharedScenarios.BindOneWay.MultipleSameTypeBindings.MyView target) { // BindOneWay: LastName -> LastNameText var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.MSTB_CFP#BindOneWayDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.MSTB_CFP#BindOneWayDispatch.g.verified.cs index 71d1943..28e8da1 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.MSTB_CFP#BindOneWayDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.MSTB_CFP#BindOneWayDispatch.g.verified.cs @@ -21,21 +21,21 @@ internal static partial class __ReactiveUIGeneratedBindings [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (callerLineNumber == 134 + if (callerLineNumber == 110 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) { - return __BindOneWay_0000177DD18BA19C(source, target); + return __BindOneWay_0000177DD18B9EB4(source, target); } - else if (callerLineNumber == 135 + else if (callerLineNumber == 111 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) { - return __BindOneWay_0000177D9FC04813(source, target); + return __BindOneWay_0000177D9FC0452B(source, target); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindOneWay_0000177DD18BA19C(global::SharedScenarios.BindOneWay.MultipleSameTypeBindings.MyViewModel source, global::SharedScenarios.BindOneWay.MultipleSameTypeBindings.MyView target) + private static global::System.IDisposable __BindOneWay_0000177DD18B9EB4(global::SharedScenarios.BindOneWay.MultipleSameTypeBindings.MyViewModel source, global::SharedScenarios.BindOneWay.MultipleSameTypeBindings.MyView target) { // BindOneWay: FirstName -> FirstNameText var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( @@ -50,7 +50,7 @@ internal static partial class __ReactiveUIGeneratedBindings }); } - private static global::System.IDisposable __BindOneWay_0000177D9FC04813(global::SharedScenarios.BindOneWay.MultipleSameTypeBindings.MyViewModel source, global::SharedScenarios.BindOneWay.MultipleSameTypeBindings.MyView target) + private static global::System.IDisposable __BindOneWay_0000177D9FC0452B(global::SharedScenarios.BindOneWay.MultipleSameTypeBindings.MyViewModel source, global::SharedScenarios.BindOneWay.MultipleSameTypeBindings.MyView target) { // BindOneWay: LastName -> LastNameText var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.ReactiveObject_Source#BindOneWayDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.ReactiveObject_Source#BindOneWayDispatch.g.verified.cs index 214d567..d7ec68e 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.ReactiveObject_Source#BindOneWayDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.ReactiveObject_Source#BindOneWayDispatch.g.verified.cs @@ -29,13 +29,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (sourcePropertyExpression == "x => x.Name" && targetPropertyExpression == "x => x.NameText") { - return __BindOneWay_7FFFEB54CB43770E(source, target); + return __BindOneWay_7FFFEB54CB43751E(source, target); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindOneWay_7FFFEB54CB43770E(global::SharedScenarios.BindOneWay.ReactiveObjectSource.MyViewModel source, global::SharedScenarios.BindOneWay.ReactiveObjectSource.MyView target) + private static global::System.IDisposable __BindOneWay_7FFFEB54CB43751E(global::SharedScenarios.BindOneWay.ReactiveObjectSource.MyViewModel source, global::SharedScenarios.BindOneWay.ReactiveObjectSource.MyView target) { // BindOneWay: Name -> NameText var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.SP_I2I#BindOneWayDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.SP_I2I#BindOneWayDispatch.g.verified.cs index 82dbc73..add0eee 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.SP_I2I#BindOneWayDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.SP_I2I#BindOneWayDispatch.g.verified.cs @@ -29,13 +29,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (sourcePropertyExpression == "x => x.Count" && targetPropertyExpression == "x => x.DisplayCount") { - return __BindOneWay_7FFFCFD371F7E4B3(source, target); + return __BindOneWay_7FFFCFD371F7E2C3(source, target); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindOneWay_7FFFCFD371F7E4B3(global::SharedScenarios.BindOneWay.SinglePropertyIntToInt.MyViewModel source, global::SharedScenarios.BindOneWay.SinglePropertyIntToInt.MyView target) + private static global::System.IDisposable __BindOneWay_7FFFCFD371F7E2C3(global::SharedScenarios.BindOneWay.SinglePropertyIntToInt.MyViewModel source, global::SharedScenarios.BindOneWay.SinglePropertyIntToInt.MyView target) { // BindOneWay: Count -> DisplayCount var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.SP_S2S#BindOneWayDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.SP_S2S#BindOneWayDispatch.g.verified.cs index 2319483..6592f05 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.SP_S2S#BindOneWayDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.SP_S2S#BindOneWayDispatch.g.verified.cs @@ -29,13 +29,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (sourcePropertyExpression == "x => x.Name" && targetPropertyExpression == "x => x.NameText") { - return __BindOneWay_7FFFD267615F289E(source, target); + return __BindOneWay_7FFFD267615F26AE(source, target); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindOneWay_7FFFD267615F289E(global::SharedScenarios.BindOneWay.SinglePropertyStringToString.MyViewModel source, global::SharedScenarios.BindOneWay.SinglePropertyStringToString.MyView target) + private static global::System.IDisposable __BindOneWay_7FFFD267615F26AE(global::SharedScenarios.BindOneWay.SinglePropertyStringToString.MyViewModel source, global::SharedScenarios.BindOneWay.SinglePropertyStringToString.MyView target) { // BindOneWay: Name -> NameText var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.SP_S2S_CFP#BindOneWayDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.SP_S2S_CFP#BindOneWayDispatch.g.verified.cs index c7e84b9..0cc1d60 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.SP_S2S_CFP#BindOneWayDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.SP_S2S_CFP#BindOneWayDispatch.g.verified.cs @@ -21,16 +21,16 @@ internal static partial class __ReactiveUIGeneratedBindings [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (callerLineNumber == 88 + if (callerLineNumber == 72 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) { - return __BindOneWay_7FFFD267615F289E(source, target); + return __BindOneWay_7FFFD267615F26AE(source, target); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindOneWay_7FFFD267615F289E(global::SharedScenarios.BindOneWay.SinglePropertyStringToString.MyViewModel source, global::SharedScenarios.BindOneWay.SinglePropertyStringToString.MyView target) + private static global::System.IDisposable __BindOneWay_7FFFD267615F26AE(global::SharedScenarios.BindOneWay.SinglePropertyStringToString.MyViewModel source, global::SharedScenarios.BindOneWay.SinglePropertyStringToString.MyView target) { // BindOneWay: Name -> NameText var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.SP_WC#BindOneWayDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.SP_WC#BindOneWayDispatch.g.verified.cs index d9842b3..9677cf4 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.SP_WC#BindOneWayDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.SP_WC#BindOneWayDispatch.g.verified.cs @@ -30,13 +30,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (sourcePropertyExpression == "x => x.Count" && targetPropertyExpression == "x => x.CountText") { - return __BindOneWay_7FFFE88AB8C052CB(source, target, conversionFunc); + return __BindOneWay_7FFFE88AB8C050DB(source, target, conversionFunc); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindOneWay_7FFFE88AB8C052CB(global::SharedScenarios.BindOneWay.SinglePropertyWithConverter.MyViewModel source, global::SharedScenarios.BindOneWay.SinglePropertyWithConverter.MyView target, global::System.Func conversionFunc) + private static global::System.IDisposable __BindOneWay_7FFFE88AB8C050DB(global::SharedScenarios.BindOneWay.SinglePropertyWithConverter.MyViewModel source, global::SharedScenarios.BindOneWay.SinglePropertyWithConverter.MyView target, global::System.Func conversionFunc) { // BindOneWay: Count -> CountText (with conversion) var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.SP_WCSched#BindOneWayDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.SP_WCSched#BindOneWayDispatch.g.verified.cs index 7b31ebf..2528cc2 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.SP_WCSched#BindOneWayDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.SP_WCSched#BindOneWayDispatch.g.verified.cs @@ -31,13 +31,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (sourcePropertyExpression == "x => x.Count" && targetPropertyExpression == "x => x.CountText") { - return __BindOneWay_7FFFED3E0F13A733(source, target, conversionFunc, scheduler); + return __BindOneWay_7FFFED3E0F13A543(source, target, conversionFunc, scheduler); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindOneWay_7FFFED3E0F13A733(global::SharedScenarios.BindOneWay.SinglePropertyWithConverterAndScheduler.MyViewModel source, global::SharedScenarios.BindOneWay.SinglePropertyWithConverterAndScheduler.MyView target, global::System.Func conversionFunc, global::System.Reactive.Concurrency.IScheduler scheduler) + private static global::System.IDisposable __BindOneWay_7FFFED3E0F13A543(global::SharedScenarios.BindOneWay.SinglePropertyWithConverterAndScheduler.MyViewModel source, global::SharedScenarios.BindOneWay.SinglePropertyWithConverterAndScheduler.MyView target, global::System.Func conversionFunc, global::System.Reactive.Concurrency.IScheduler scheduler) { // BindOneWay: Count -> CountText (with conversion) (with scheduler) var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.SP_WithScheduler#BindOneWayDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.SP_WithScheduler#BindOneWayDispatch.g.verified.cs index 286e656..db2a234 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.SP_WithScheduler#BindOneWayDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BOG.SP_WithScheduler#BindOneWayDispatch.g.verified.cs @@ -30,13 +30,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (sourcePropertyExpression == "x => x.Name" && targetPropertyExpression == "x => x.NameText") { - return __BindOneWay_000023CFCD42C66A(source, target, scheduler); + return __BindOneWay_000023CFCD42C47A(source, target, scheduler); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindOneWay_000023CFCD42C66A(global::SharedScenarios.BindOneWay.SinglePropertyWithScheduler.MyViewModel source, global::SharedScenarios.BindOneWay.SinglePropertyWithScheduler.MyView target, global::System.Reactive.Concurrency.IScheduler scheduler) + private static global::System.IDisposable __BindOneWay_000023CFCD42C47A(global::SharedScenarios.BindOneWay.SinglePropertyWithScheduler.MyViewModel source, global::SharedScenarios.BindOneWay.SinglePropertyWithScheduler.MyView target, global::System.Reactive.Concurrency.IScheduler scheduler) { // BindOneWay: Name -> NameText (with scheduler) var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.MB#BindTwoWayDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.MB#BindTwoWayDispatch.g.verified.cs index 0a9d22e..8814031 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.MB#BindTwoWayDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.MB#BindTwoWayDispatch.g.verified.cs @@ -29,13 +29,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (sourcePropertyExpression == "x => x.Name" && targetPropertyExpression == "x => x.NameText") { - return __BindTwoWay_00002294527D5234(source, target); + return __BindTwoWay_00002294527D4F4C(source, target); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindTwoWay_00002294527D5234(global::SharedScenarios.BindTwoWay.MultipleBindings.MyViewModel source, global::SharedScenarios.BindTwoWay.MultipleBindings.MyView target) + private static global::System.IDisposable __BindTwoWay_00002294527D4F4C(global::SharedScenarios.BindTwoWay.MultipleBindings.MyViewModel source, global::SharedScenarios.BindTwoWay.MultipleBindings.MyView target) { // BindTwoWay: Name <-> NameText var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( @@ -83,13 +83,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (sourcePropertyExpression == "x => x.Age" && targetPropertyExpression == "x => x.AgeDisplay") { - return __BindTwoWay_0000229444056693(source, target); + return __BindTwoWay_00002294440563AB(source, target); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindTwoWay_0000229444056693(global::SharedScenarios.BindTwoWay.MultipleBindings.MyViewModel source, global::SharedScenarios.BindTwoWay.MultipleBindings.MyView target) + private static global::System.IDisposable __BindTwoWay_00002294440563AB(global::SharedScenarios.BindTwoWay.MultipleBindings.MyViewModel source, global::SharedScenarios.BindTwoWay.MultipleBindings.MyView target) { // BindTwoWay: Age <-> AgeDisplay var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.MSTB#BindTwoWayDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.MSTB#BindTwoWayDispatch.g.verified.cs index 3002b44..e154616 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.MSTB#BindTwoWayDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.MSTB#BindTwoWayDispatch.g.verified.cs @@ -29,18 +29,18 @@ internal static partial class __ReactiveUIGeneratedBindings if (sourcePropertyExpression == "x => x.FirstName" && targetPropertyExpression == "x => x.FirstNameText") { - return __BindTwoWay_7FFFD5F622CF3052(source, target); + return __BindTwoWay_7FFFD5F622CF2D6A(source, target); } else if (sourcePropertyExpression == "x => x.LastName" && targetPropertyExpression == "x => x.LastNameText") { - return __BindTwoWay_7FFFD5F5F103D6C9(source, target); + return __BindTwoWay_7FFFD5F5F103D3E1(source, target); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindTwoWay_7FFFD5F622CF3052(global::SharedScenarios.BindTwoWay.MultipleSameTypeBindings.MyViewModel source, global::SharedScenarios.BindTwoWay.MultipleSameTypeBindings.MyView target) + private static global::System.IDisposable __BindTwoWay_7FFFD5F622CF2D6A(global::SharedScenarios.BindTwoWay.MultipleSameTypeBindings.MyViewModel source, global::SharedScenarios.BindTwoWay.MultipleSameTypeBindings.MyView target) { // BindTwoWay: FirstName <-> FirstNameText var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( @@ -68,7 +68,7 @@ internal static partial class __ReactiveUIGeneratedBindings return new global::ReactiveUI.Binding.Observables.CompositeDisposable2(d1, d2); } - private static global::System.IDisposable __BindTwoWay_7FFFD5F5F103D6C9(global::SharedScenarios.BindTwoWay.MultipleSameTypeBindings.MyViewModel source, global::SharedScenarios.BindTwoWay.MultipleSameTypeBindings.MyView target) + private static global::System.IDisposable __BindTwoWay_7FFFD5F5F103D3E1(global::SharedScenarios.BindTwoWay.MultipleSameTypeBindings.MyViewModel source, global::SharedScenarios.BindTwoWay.MultipleSameTypeBindings.MyView target) { // BindTwoWay: LastName <-> LastNameText var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.MSTB_CFP#BindTwoWayDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.MSTB_CFP#BindTwoWayDispatch.g.verified.cs index 6959612..a0568bb 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.MSTB_CFP#BindTwoWayDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.MSTB_CFP#BindTwoWayDispatch.g.verified.cs @@ -21,21 +21,21 @@ internal static partial class __ReactiveUIGeneratedBindings [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (callerLineNumber == 134 + if (callerLineNumber == 110 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) { - return __BindTwoWay_7FFFD5F622CF3052(source, target); + return __BindTwoWay_7FFFD5F622CF2D6A(source, target); } - else if (callerLineNumber == 135 + else if (callerLineNumber == 111 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) { - return __BindTwoWay_7FFFD5F5F103D6C9(source, target); + return __BindTwoWay_7FFFD5F5F103D3E1(source, target); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindTwoWay_7FFFD5F622CF3052(global::SharedScenarios.BindTwoWay.MultipleSameTypeBindings.MyViewModel source, global::SharedScenarios.BindTwoWay.MultipleSameTypeBindings.MyView target) + private static global::System.IDisposable __BindTwoWay_7FFFD5F622CF2D6A(global::SharedScenarios.BindTwoWay.MultipleSameTypeBindings.MyViewModel source, global::SharedScenarios.BindTwoWay.MultipleSameTypeBindings.MyView target) { // BindTwoWay: FirstName <-> FirstNameText var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( @@ -63,7 +63,7 @@ internal static partial class __ReactiveUIGeneratedBindings return new global::ReactiveUI.Binding.Observables.CompositeDisposable2(d1, d2); } - private static global::System.IDisposable __BindTwoWay_7FFFD5F5F103D6C9(global::SharedScenarios.BindTwoWay.MultipleSameTypeBindings.MyViewModel source, global::SharedScenarios.BindTwoWay.MultipleSameTypeBindings.MyView target) + private static global::System.IDisposable __BindTwoWay_7FFFD5F5F103D3E1(global::SharedScenarios.BindTwoWay.MultipleSameTypeBindings.MyViewModel source, global::SharedScenarios.BindTwoWay.MultipleSameTypeBindings.MyView target) { // BindTwoWay: LastName <-> LastNameText var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.MixedWithBindOneWay#BindOneWayDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.MixedWithBindOneWay#BindOneWayDispatch.g.verified.cs index 45f1e87..e411eae 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.MixedWithBindOneWay#BindOneWayDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.MixedWithBindOneWay#BindOneWayDispatch.g.verified.cs @@ -29,13 +29,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (sourcePropertyExpression == "x => x.ReadOnlyCount" && targetPropertyExpression == "x => x.CountDisplay") { - return __BindOneWay_7FFFF5775C63D10F(source, target); + return __BindOneWay_7FFFF5775C63CE27(source, target); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindOneWay_7FFFF5775C63D10F(global::SharedScenarios.BindTwoWay.MixedWithBindOneWay.MyViewModel source, global::SharedScenarios.BindTwoWay.MixedWithBindOneWay.MyView target) + private static global::System.IDisposable __BindOneWay_7FFFF5775C63CE27(global::SharedScenarios.BindTwoWay.MixedWithBindOneWay.MyViewModel source, global::SharedScenarios.BindTwoWay.MixedWithBindOneWay.MyView target) { // BindOneWay: ReadOnlyCount -> CountDisplay var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.MixedWithBindOneWay#BindTwoWayDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.MixedWithBindOneWay#BindTwoWayDispatch.g.verified.cs index ef484b3..8982ab0 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.MixedWithBindOneWay#BindTwoWayDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.MixedWithBindOneWay#BindTwoWayDispatch.g.verified.cs @@ -29,13 +29,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (sourcePropertyExpression == "x => x.Name" && targetPropertyExpression == "x => x.NameText") { - return __BindTwoWay_7FFFF577D0B63EE3(source, target); + return __BindTwoWay_7FFFF577D0B63BFB(source, target); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindTwoWay_7FFFF577D0B63EE3(global::SharedScenarios.BindTwoWay.MixedWithBindOneWay.MyViewModel source, global::SharedScenarios.BindTwoWay.MixedWithBindOneWay.MyView target) + private static global::System.IDisposable __BindTwoWay_7FFFF577D0B63BFB(global::SharedScenarios.BindTwoWay.MixedWithBindOneWay.MyViewModel source, global::SharedScenarios.BindTwoWay.MixedWithBindOneWay.MyView target) { // BindTwoWay: Name <-> NameText var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.ReactiveObject_Both#BindTwoWayDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.ReactiveObject_Both#BindTwoWayDispatch.g.verified.cs index ccedf51..903f002 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.ReactiveObject_Both#BindTwoWayDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.ReactiveObject_Both#BindTwoWayDispatch.g.verified.cs @@ -29,13 +29,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (sourcePropertyExpression == "x => x.Name" && targetPropertyExpression == "x => x.NameText") { - return __BindTwoWay_000022F0C1901F4C(source, target); + return __BindTwoWay_000022F0C1901D5C(source, target); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindTwoWay_000022F0C1901F4C(global::SharedScenarios.BindTwoWay.ReactiveObjectBoth.MyViewModel source, global::SharedScenarios.BindTwoWay.ReactiveObjectBoth.MyView target) + private static global::System.IDisposable __BindTwoWay_000022F0C1901D5C(global::SharedScenarios.BindTwoWay.ReactiveObjectBoth.MyViewModel source, global::SharedScenarios.BindTwoWay.ReactiveObjectBoth.MyView target) { // BindTwoWay: Name <-> NameText var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.SP_I2I#BindTwoWayDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.SP_I2I#BindTwoWayDispatch.g.verified.cs index 1a676a6..2c1b0ea 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.SP_I2I#BindTwoWayDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.SP_I2I#BindTwoWayDispatch.g.verified.cs @@ -29,13 +29,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (sourcePropertyExpression == "x => x.Count" && targetPropertyExpression == "x => x.DisplayCount") { - return __BindTwoWay_000002183E7190F5(source, target); + return __BindTwoWay_000002183E718F05(source, target); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindTwoWay_000002183E7190F5(global::SharedScenarios.BindTwoWay.SinglePropertyIntToInt.MyViewModel source, global::SharedScenarios.BindTwoWay.SinglePropertyIntToInt.MyView target) + private static global::System.IDisposable __BindTwoWay_000002183E718F05(global::SharedScenarios.BindTwoWay.SinglePropertyIntToInt.MyViewModel source, global::SharedScenarios.BindTwoWay.SinglePropertyIntToInt.MyView target) { // BindTwoWay: Count <-> DisplayCount var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.SP_S2S#BindTwoWayDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.SP_S2S#BindTwoWayDispatch.g.verified.cs index 466c569..6f22cdf 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.SP_S2S#BindTwoWayDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.SP_S2S#BindTwoWayDispatch.g.verified.cs @@ -29,13 +29,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (sourcePropertyExpression == "x => x.Name" && targetPropertyExpression == "x => x.NameText") { - return __BindTwoWay_7FFFEF88F2A77B00(source, target); + return __BindTwoWay_7FFFEF88F2A77910(source, target); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindTwoWay_7FFFEF88F2A77B00(global::SharedScenarios.BindTwoWay.SinglePropertyStringToString.MyViewModel source, global::SharedScenarios.BindTwoWay.SinglePropertyStringToString.MyView target) + private static global::System.IDisposable __BindTwoWay_7FFFEF88F2A77910(global::SharedScenarios.BindTwoWay.SinglePropertyStringToString.MyViewModel source, global::SharedScenarios.BindTwoWay.SinglePropertyStringToString.MyView target) { // BindTwoWay: Name <-> NameText var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.SP_S2S_CFP#BindTwoWayDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.SP_S2S_CFP#BindTwoWayDispatch.g.verified.cs index 79e2982..0bb161b 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.SP_S2S_CFP#BindTwoWayDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.SP_S2S_CFP#BindTwoWayDispatch.g.verified.cs @@ -21,16 +21,16 @@ internal static partial class __ReactiveUIGeneratedBindings [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (callerLineNumber == 88 + if (callerLineNumber == 72 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) { - return __BindTwoWay_7FFFEF88F2A77B00(source, target); + return __BindTwoWay_7FFFEF88F2A77910(source, target); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindTwoWay_7FFFEF88F2A77B00(global::SharedScenarios.BindTwoWay.SinglePropertyStringToString.MyViewModel source, global::SharedScenarios.BindTwoWay.SinglePropertyStringToString.MyView target) + private static global::System.IDisposable __BindTwoWay_7FFFEF88F2A77910(global::SharedScenarios.BindTwoWay.SinglePropertyStringToString.MyViewModel source, global::SharedScenarios.BindTwoWay.SinglePropertyStringToString.MyView target) { // BindTwoWay: Name <-> NameText var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.SP_WC#BindTwoWayDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.SP_WC#BindTwoWayDispatch.g.verified.cs index 3981c45..b4eb712 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.SP_WC#BindTwoWayDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.SP_WC#BindTwoWayDispatch.g.verified.cs @@ -31,13 +31,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (sourcePropertyExpression == "x => x.Count" && targetPropertyExpression == "x => x.CountText") { - return __BindTwoWay_000013957A2E95F4(source, target, sourceToTargetConv, targetToSourceConv); + return __BindTwoWay_000013957A2E9404(source, target, sourceToTargetConv, targetToSourceConv); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindTwoWay_000013957A2E95F4(global::SharedScenarios.BindTwoWay.SinglePropertyWithConverters.MyViewModel source, global::SharedScenarios.BindTwoWay.SinglePropertyWithConverters.MyView target, global::System.Func sourceToTargetConv, global::System.Func targetToSourceConv) + private static global::System.IDisposable __BindTwoWay_000013957A2E9404(global::SharedScenarios.BindTwoWay.SinglePropertyWithConverters.MyViewModel source, global::SharedScenarios.BindTwoWay.SinglePropertyWithConverters.MyView target, global::System.Func sourceToTargetConv, global::System.Func targetToSourceConv) { // BindTwoWay: Count <-> CountText (with conversion) var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.SP_WCSched#BindTwoWayDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.SP_WCSched#BindTwoWayDispatch.g.verified.cs index c8d7fdf..89302fe 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.SP_WCSched#BindTwoWayDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.SP_WCSched#BindTwoWayDispatch.g.verified.cs @@ -32,13 +32,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (sourcePropertyExpression == "x => x.Count" && targetPropertyExpression == "x => x.CountText") { - return __BindTwoWay_00000972B7EA34FC(source, target, sourceToTargetConv, targetToSourceConv, scheduler); + return __BindTwoWay_00000972B7EA330C(source, target, sourceToTargetConv, targetToSourceConv, scheduler); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindTwoWay_00000972B7EA34FC(global::SharedScenarios.BindTwoWay.SinglePropertyWithConvertersAndScheduler.MyViewModel source, global::SharedScenarios.BindTwoWay.SinglePropertyWithConvertersAndScheduler.MyView target, global::System.Func sourceToTargetConv, global::System.Func targetToSourceConv, global::System.Reactive.Concurrency.IScheduler scheduler) + private static global::System.IDisposable __BindTwoWay_00000972B7EA330C(global::SharedScenarios.BindTwoWay.SinglePropertyWithConvertersAndScheduler.MyViewModel source, global::SharedScenarios.BindTwoWay.SinglePropertyWithConvertersAndScheduler.MyView target, global::System.Func sourceToTargetConv, global::System.Func targetToSourceConv, global::System.Reactive.Concurrency.IScheduler scheduler) { // BindTwoWay: Count <-> CountText (with conversion) (with scheduler) var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.SP_WithScheduler#BindTwoWayDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.SP_WithScheduler#BindTwoWayDispatch.g.verified.cs index 993f4bd..2af309e 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.SP_WithScheduler#BindTwoWayDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BTG.SP_WithScheduler#BindTwoWayDispatch.g.verified.cs @@ -30,13 +30,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (sourcePropertyExpression == "x => x.Name" && targetPropertyExpression == "x => x.NameText") { - return __BindTwoWay_7FFFF863C3AFAEBC(source, target, scheduler); + return __BindTwoWay_7FFFF863C3AFACCC(source, target, scheduler); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindTwoWay_7FFFF863C3AFAEBC(global::SharedScenarios.BindTwoWay.SinglePropertyWithScheduler.MyViewModel source, global::SharedScenarios.BindTwoWay.SinglePropertyWithScheduler.MyView target, global::System.Reactive.Concurrency.IScheduler scheduler) + private static global::System.IDisposable __BindTwoWay_7FFFF863C3AFACCC(global::SharedScenarios.BindTwoWay.SinglePropertyWithScheduler.MyViewModel source, global::SharedScenarios.BindTwoWay.SinglePropertyWithScheduler.MyView target, global::System.Reactive.Concurrency.IScheduler scheduler) { // BindTwoWay: Name <-> NameText (with scheduler) var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BToG.DifferingTypes#BindToDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BToG.DifferingTypes#BindToDispatch.g.verified.cs index 0417086..afbf7ae 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BToG.DifferingTypes#BindToDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BToG.DifferingTypes#BindToDispatch.g.verified.cs @@ -25,13 +25,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (propertyExpression == "x => x.Caption") { - return __BindTo_7FFFF0EE063CE422(source, target); + return __BindTo_7FFFF0EE063CE2EC(source, target); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindTo_7FFFF0EE063CE422(global::System.IObservable source, global::SharedScenarios.BindTo.DifferingTypes.MyView target) + private static global::System.IDisposable __BindTo_7FFFF0EE063CE2EC(global::System.IObservable source, global::SharedScenarios.BindTo.DifferingTypes.MyView target) { // BindTo: observable -> Caption return global::ReactiveUI.Binding.Observables.RxBindingExtensions.Subscribe(source, value => diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BToG.SameTypeString#BindToDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BToG.SameTypeString#BindToDispatch.g.verified.cs index 50e55cf..2e55d9d 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BToG.SameTypeString#BindToDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BToG.SameTypeString#BindToDispatch.g.verified.cs @@ -25,13 +25,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (propertyExpression == "x => x.Caption") { - return __BindTo_000016A7FA446C30(source, target); + return __BindTo_000016A7FA446AFA(source, target); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindTo_000016A7FA446C30(global::System.IObservable source, global::SharedScenarios.BindTo.SameTypeString.MyView target) + private static global::System.IDisposable __BindTo_000016A7FA446AFA(global::System.IObservable source, global::SharedScenarios.BindTo.SameTypeString.MyView target) { // BindTo: observable -> Caption return global::ReactiveUI.Binding.Observables.RxBindingExtensions.Subscribe(source, value => diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BToG.SameTypeString_CFP#BindToDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BToG.SameTypeString_CFP#BindToDispatch.g.verified.cs index 589df11..ce39d57 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BToG.SameTypeString_CFP#BindToDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BToG.SameTypeString_CFP#BindToDispatch.g.verified.cs @@ -20,16 +20,16 @@ internal static partial class __ReactiveUIGeneratedBindings [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (callerLineNumber == 56 + if (callerLineNumber == 46 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) { - return __BindTo_000016A7FA446C30(source, target); + return __BindTo_000016A7FA446AFA(source, target); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindTo_000016A7FA446C30(global::System.IObservable source, global::SharedScenarios.BindTo.SameTypeString.MyView target) + private static global::System.IDisposable __BindTo_000016A7FA446AFA(global::System.IObservable source, global::SharedScenarios.BindTo.SameTypeString.MyView target) { // BindTo: observable -> Caption return global::ReactiveUI.Binding.Observables.RxBindingExtensions.Subscribe(source, value => diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BToG.WCOverride#BindToDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BToG.WCOverride#BindToDispatch.g.verified.cs index 3b742de..b933206 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BToG.WCOverride#BindToDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BToG.WCOverride#BindToDispatch.g.verified.cs @@ -26,13 +26,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (propertyExpression == "x => x.Caption") { - return __BindTo_7FFFF5030A82AE32(source, target, converterOverride); + return __BindTo_7FFFF5030A82ACFC(source, target, converterOverride); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindTo_7FFFF5030A82AE32(global::System.IObservable source, global::SharedScenarios.BindTo.WithConverterOverride.MyView target, global::ReactiveUI.Binding.IBindingTypeConverter converterOverride) + private static global::System.IDisposable __BindTo_7FFFF5030A82ACFC(global::System.IObservable source, global::SharedScenarios.BindTo.WithConverterOverride.MyView target, global::ReactiveUI.Binding.IBindingTypeConverter converterOverride) { // BindTo: observable -> Caption return global::ReactiveUI.Binding.Observables.RxBindingExtensions.Subscribe(source, value => diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BToG.WithConversionHint#BindToDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BToG.WithConversionHint#BindToDispatch.g.verified.cs index 573f548..88f72ad 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BToG.WithConversionHint#BindToDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BToG.WithConversionHint#BindToDispatch.g.verified.cs @@ -26,13 +26,13 @@ internal static partial class __ReactiveUIGeneratedBindings if (propertyExpression == "x => x.Caption") { - return __BindTo_7FFFC579FC79786E(source, target, conversionHint); + return __BindTo_7FFFC579FC797738(source, target, conversionHint); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IDisposable __BindTo_7FFFC579FC79786E(global::System.IObservable source, global::SharedScenarios.BindTo.WithConversionHint.MyView target, object conversionHint) + private static global::System.IDisposable __BindTo_7FFFC579FC797738(global::System.IObservable source, global::SharedScenarios.BindTo.WithConversionHint.MyView target, object conversionHint) { // BindTo: observable -> Caption return global::ReactiveUI.Binding.Observables.RxBindingExtensions.Subscribe(source, value => diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BindCommandGeneratorTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BindCommandGeneratorTests.cs index 748fe79..7b768c1 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BindCommandGeneratorTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BindCommandGeneratorTests.cs @@ -7,14 +7,10 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests; -/// -/// Snapshot tests for BindCommand invocation generation. -/// +/// Snapshot tests for BindCommand invocation generation. public class BindCommandGeneratorTests { - /// - /// Verifies BindCommand with a basic button and no parameter. - /// + /// Verifies BindCommand with a basic button and no parameter. /// A task representing the asynchronous test operation. [Test] public async Task BasicNoParam() @@ -26,9 +22,7 @@ public async Task BasicNoParam() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies BindCommand with an IObservable parameter. - /// + /// Verifies BindCommand with an IObservable parameter. /// A task representing the asynchronous test operation. [Test] public async Task ObservableParam() @@ -40,9 +34,7 @@ public async Task ObservableParam() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies BindCommand with an expression-based parameter. - /// + /// Verifies BindCommand with an expression-based parameter. /// A task representing the asynchronous test operation. [Test] public async Task ExpressionParam() @@ -54,9 +46,7 @@ public async Task ExpressionParam() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies BindCommand with a control that has no default event. - /// + /// Verifies BindCommand with a control that has no default event. /// A task representing the asynchronous test operation. [Test] public async Task NoEvent() diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BindGeneratorTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BindGeneratorTests.cs index e8493eb..6f38a96 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BindGeneratorTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BindGeneratorTests.cs @@ -7,14 +7,10 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests; -/// -/// Snapshot tests for Bind (view-first two-way binding) invocation generation. -/// +/// Snapshot tests for Bind (view-first two-way binding) invocation generation. public class BindGeneratorTests { - /// - /// Verifies Bind with same-type string property binding. - /// + /// Verifies Bind with same-type string property binding. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_StringToString() @@ -25,9 +21,7 @@ public async Task SingleProperty_StringToString() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies Bind with multiple bindings on the same view/vm pair. - /// + /// Verifies Bind with multiple bindings on the same view/vm pair. /// A task representing the asynchronous test operation. [Test] public async Task MultipleBindings() @@ -38,9 +32,7 @@ public async Task MultipleBindings() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies Bind with conversion functions between int and string. - /// + /// Verifies Bind with conversion functions between int and string. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_WithConverters() @@ -51,9 +43,7 @@ public async Task SingleProperty_WithConverters() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies Bind with conversion functions and a scheduler. - /// + /// Verifies Bind with conversion functions and a scheduler. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_WithConvertersAndScheduler() diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BindInteractionGeneratorTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BindInteractionGeneratorTests.cs index 4d6b327..5109f52 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BindInteractionGeneratorTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BindInteractionGeneratorTests.cs @@ -7,14 +7,10 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests; -/// -/// Snapshot tests for BindInteraction invocation generation. -/// +/// Snapshot tests for BindInteraction invocation generation. public class BindInteractionGeneratorTests { - /// - /// Verifies BindInteraction with a task-based handler. - /// + /// Verifies BindInteraction with a task-based handler. /// A task representing the asynchronous test operation. [Test] public async Task TaskHandler() @@ -29,9 +25,7 @@ await TestHelper.TestPassWithResult( await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies BindInteraction with an observable-based handler. - /// + /// Verifies BindInteraction with an observable-based handler. /// A task representing the asynchronous test operation. [Test] public async Task ObservableHandler() @@ -46,9 +40,7 @@ await TestHelper.TestPassWithResult( await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies BindInteraction with a deep property path (Child.Confirm). - /// + /// Verifies BindInteraction with a deep property path (Child.Confirm). /// A task representing the asynchronous test operation. [Test] public async Task DeepPropertyPath() @@ -63,15 +55,9 @@ await TestHelper.TestPassWithResult( await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies BindInteraction with a ViewModel that does not implement INPC. - /// + /// Verifies BindInteraction with a ViewModel that does not implement INPC. /// A task representing the asynchronous test operation. [Test] - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Minor Code Smell", - "S100:Methods and properties should be named in PascalCase", - Justification = "INPC abbreviates INotifyPropertyChanged, an established acronym matching the ReactiveUI domain terminology.")] public async Task NonINPCViewModel() { var source = SharedSourceReader.ReadScenario("BindInteraction/NonINPCViewModel"); diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BindOneWayGeneratorTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BindOneWayGeneratorTests.cs index 18a54af..1b4a71c 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BindOneWayGeneratorTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BindOneWayGeneratorTests.cs @@ -7,14 +7,13 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests; -/// -/// Snapshot tests for BindOneWay (one-way binding) invocation generation. -/// +/// Snapshot tests for BindOneWay (one-way binding) invocation generation. public class BindOneWayGeneratorTests { - /// - /// Verifies BindOneWay with same-type string property binding. - /// + /// The BindOneWayDispatch.g.cs name these tests generate against. + private const string BindOneWayDispatchgcsName = "BindOneWayDispatch.g.cs"; + + /// Verifies BindOneWay with same-type string property binding. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_StringToString() @@ -26,9 +25,7 @@ public async Task SingleProperty_StringToString() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies BindOneWay with int property binding. - /// + /// Verifies BindOneWay with int property binding. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_IntToInt() @@ -40,9 +37,7 @@ public async Task SingleProperty_IntToInt() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies BindOneWay with multiple bindings on the same source/target pair. - /// + /// Verifies BindOneWay with multiple bindings on the same source/target pair. /// A task representing the asynchronous test operation. [Test] public async Task MultipleBindings() @@ -54,9 +49,7 @@ public async Task MultipleBindings() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies BindOneWay on a ReactiveObject-based ViewModel. - /// + /// Verifies BindOneWay on a ReactiveObject-based ViewModel. /// A task representing the asynchronous test operation. [Test] public async Task ReactiveObject_Source() @@ -68,9 +61,7 @@ public async Task ReactiveObject_Source() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies BindOneWay with a conversion function from int to string. - /// + /// Verifies BindOneWay with a conversion function from int to string. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_WithConverter() @@ -82,9 +73,7 @@ public async Task SingleProperty_WithConverter() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies BindOneWay with a scheduler parameter. - /// + /// Verifies BindOneWay with a scheduler parameter. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_WithScheduler() @@ -113,9 +102,7 @@ public async Task SingleProperty_StringToString_CallerFilePath() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies BindOneWay with both a conversion function and a scheduler parameter. - /// + /// Verifies BindOneWay with both a conversion function and a scheduler parameter. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_WithConverterAndScheduler() @@ -127,9 +114,7 @@ public async Task SingleProperty_WithConverterAndScheduler() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies BindOneWay with multiple bindings sharing the same type signature to cover the else-if dispatch branch. - /// + /// Verifies BindOneWay with multiple bindings sharing the same type signature to cover the else-if dispatch branch. /// A task representing the asynchronous test operation. [Test] public async Task MultipleSameTypeBindings() @@ -141,9 +126,7 @@ public async Task MultipleSameTypeBindings() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies that BindOneWay with multiple same-type bindings generates CallerFilePath dispatch when targeting pre-C# 10. - /// + /// Verifies that BindOneWay with multiple same-type bindings generates CallerFilePath dispatch when targeting pre-C# 10. /// A task representing the asynchronous test operation. [Test] public async Task MultipleSameTypeBindings_CallerFilePath() @@ -209,7 +192,7 @@ public static void Execute(MyViewModel vm, MyView view) // The generator should not produce any BindOneWay dispatch code // because the method belongs to CustomBindingExtensions, not our extension class. await result.HasNoGeneratorDiagnostics(); - await result.DoesNotHaveGeneratedSource("BindOneWayDispatch.g.cs"); + await result.DoesNotHaveGeneratedSource(BindOneWayDispatchgcsName); } /// @@ -255,7 +238,7 @@ public static void Execute(MyViewModel vm, MyView view) // The generator should silently skip the identity lambda and produce no dispatch. await result.HasNoGeneratorDiagnostics(); - await result.DoesNotHaveGeneratedSource("BindOneWayDispatch.g.cs"); + await result.DoesNotHaveGeneratedSource(BindOneWayDispatchgcsName); } /// @@ -301,7 +284,7 @@ public static void Execute(MyViewModel vm, MyView view) // The generator should silently skip block-body lambdas and produce no dispatch. await result.HasNoGeneratorDiagnostics(); - await result.DoesNotHaveGeneratedSource("BindOneWayDispatch.g.cs"); + await result.DoesNotHaveGeneratedSource(BindOneWayDispatchgcsName); } /// @@ -347,6 +330,6 @@ public static void Execute(MyViewModel vm, MyView view) // The generator should silently skip field access lambdas and produce no dispatch. await result.HasNoGeneratorDiagnostics(); - await result.DoesNotHaveGeneratedSource("BindOneWayDispatch.g.cs"); + await result.DoesNotHaveGeneratedSource(BindOneWayDispatchgcsName); } } diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BindToGeneratorTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BindToGeneratorTests.cs index ee423d3..734efa1 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BindToGeneratorTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BindToGeneratorTests.cs @@ -7,14 +7,10 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests; -/// -/// Snapshot tests for BindTo (observable-to-property binding) invocation generation. -/// +/// Snapshot tests for BindTo (observable-to-property binding) invocation generation. public class BindToGeneratorTests { - /// - /// Verifies BindTo with a same-typed string observable and string property (direct assignment). - /// + /// Verifies BindTo with a same-typed string observable and string property (direct assignment). /// A task representing the asynchronous test operation. [Test] public async Task SameTypeString() @@ -26,9 +22,7 @@ public async Task SameTypeString() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies BindTo coerces differing source/target types via the converter registry. - /// + /// Verifies BindTo coerces differing source/target types via the converter registry. /// A task representing the asynchronous test operation. [Test] public async Task DifferingTypes() @@ -40,9 +34,7 @@ public async Task DifferingTypes() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies BindTo with an explicit IBindingTypeConverter override. - /// + /// Verifies BindTo with an explicit IBindingTypeConverter override. /// A task representing the asynchronous test operation. [Test] public async Task WithConverterOverride() @@ -54,9 +46,7 @@ public async Task WithConverterOverride() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies BindTo with a conversion hint forwarded to the resolved converter. - /// + /// Verifies BindTo with a conversion hint forwarded to the resolved converter. /// A task representing the asynchronous test operation. [Test] public async Task WithConversionHint() diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BindTwoWayGeneratorTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BindTwoWayGeneratorTests.cs index ce5a3ab..cd95f34 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BindTwoWayGeneratorTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/BindTwoWayGeneratorTests.cs @@ -7,14 +7,10 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests; -/// -/// Snapshot tests for BindTwoWay (two-way binding) invocation generation. -/// +/// Snapshot tests for BindTwoWay (two-way binding) invocation generation. public class BindTwoWayGeneratorTests { - /// - /// Verifies BindTwoWay with same-type string property binding. - /// + /// Verifies BindTwoWay with same-type string property binding. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_StringToString() @@ -26,9 +22,7 @@ public async Task SingleProperty_StringToString() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies BindTwoWay with int property binding. - /// + /// Verifies BindTwoWay with int property binding. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_IntToInt() @@ -40,9 +34,7 @@ public async Task SingleProperty_IntToInt() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies BindTwoWay with multiple bindings on the same source/target pair. - /// + /// Verifies BindTwoWay with multiple bindings on the same source/target pair. /// A task representing the asynchronous test operation. [Test] public async Task MultipleBindings() @@ -54,9 +46,7 @@ public async Task MultipleBindings() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies BindTwoWay on a ReactiveObject-based ViewModel and View. - /// + /// Verifies BindTwoWay on a ReactiveObject-based ViewModel and View. /// A task representing the asynchronous test operation. [Test] public async Task ReactiveObject_Both() @@ -68,9 +58,7 @@ public async Task ReactiveObject_Both() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies BindTwoWay combined with BindOneWay in the same compilation. - /// + /// Verifies BindTwoWay combined with BindOneWay in the same compilation. /// A task representing the asynchronous test operation. [Test] public async Task MixedWithBindOneWay() @@ -82,9 +70,7 @@ public async Task MixedWithBindOneWay() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies BindTwoWay with conversion functions between int and string. - /// + /// Verifies BindTwoWay with conversion functions between int and string. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_WithConverters() @@ -96,9 +82,7 @@ public async Task SingleProperty_WithConverters() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies BindTwoWay with a scheduler parameter. - /// + /// Verifies BindTwoWay with a scheduler parameter. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_WithScheduler() @@ -127,9 +111,7 @@ public async Task SingleProperty_StringToString_CallerFilePath() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies BindTwoWay with both conversion functions and a scheduler parameter. - /// + /// Verifies BindTwoWay with both conversion functions and a scheduler parameter. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_WithConvertersAndScheduler() @@ -141,9 +123,7 @@ public async Task SingleProperty_WithConvertersAndScheduler() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies BindTwoWay with multiple bindings sharing the same type signature to cover the else-if dispatch branch. - /// + /// Verifies BindTwoWay with multiple bindings sharing the same type signature to cover the else-if dispatch branch. /// A task representing the asynchronous test operation. [Test] public async Task MultipleSameTypeBindings() @@ -155,9 +135,7 @@ public async Task MultipleSameTypeBindings() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies that BindTwoWay with multiple same-type bindings generates CallerFilePath dispatch when targeting pre-C# 10. - /// + /// Verifies that BindTwoWay with multiple same-type bindings generates CallerFilePath dispatch when targeting pre-C# 10. /// A task representing the asynchronous test operation. [Test] public async Task MultipleSameTypeBindings_CallerFilePath() diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/BindCodeGeneratorHelperTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/BindCodeGeneratorHelperTests.cs index 1b9f27e..1b42208 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/BindCodeGeneratorHelperTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/BindCodeGeneratorHelperTests.cs @@ -10,14 +10,34 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests.CodeGeneration; -/// -/// Tests for helper methods. -/// +/// Tests for helper methods. public class BindCodeGeneratorHelperTests { - /// - /// Verifies GroupByTypeSignature groups invocations with the same type signature. - /// + /// The fully qualified name of the View type used by these tests. + private const string ViewTypeName = "global::TestApp.View"; + + /// The fully qualified name of the VM type used by these tests. + private const string VMTypeName = "global::TestApp.VM"; + + /// The IReactiveBinding name these tests generate against. + private const string IReactiveBindingName = "IReactiveBinding"; + + /// The vmToViewConverter name these tests generate against. + private const string ViewModelToViewConverterName = "viewModelToViewConverter"; + + /// The viewToVmConverter name these tests generate against. + private const string ViewToViewModelConverterName = "viewToViewModelConverter"; + + /// The scheduler name these tests generate against. + private const string SchedulerName = "scheduler"; + + /// The fully qualified name of the MyView type used by these tests. + private const string MyViewTypeName = "global::TestApp.MyView"; + + /// The fully qualified name of the String type used by these tests. + private const string StringTypeName = "global::System.String"; + + /// Verifies GroupByTypeSignature groups invocations with the same type signature. /// A task representing the asynchronous test operation. [Test] public async Task GroupByTypeSignature_SameSignature_GroupedTogether() @@ -28,13 +48,12 @@ public async Task GroupByTypeSignature_SameSignature_GroupedTogether() var groups = BindCodeGenerator.GroupByTypeSignature(invocations); + const int expectedInvocationCount = 2; await Assert.That(groups.Count).IsEqualTo(1); - await Assert.That(groups[0].Invocations.Length).IsEqualTo(2); + await Assert.That(groups[0].Invocations.Length).IsEqualTo(expectedInvocationCount); } - /// - /// Verifies GroupByTypeSignature separates invocations with different source types. - /// + /// Verifies GroupByTypeSignature separates invocations with different source types. /// A task representing the asynchronous test operation. [Test] public async Task GroupByTypeSignature_DifferentSourceTypes_SeparateGroups() @@ -47,14 +66,13 @@ public async Task GroupByTypeSignature_DifferentSourceTypes_SeparateGroups() methodName: "Bind"); var invocations = ImmutableArray.Create(inv1, inv2); + const int ExpectedGroupCount = 2; var groups = BindCodeGenerator.GroupByTypeSignature(invocations); - await Assert.That(groups.Count).IsEqualTo(2); + await Assert.That(groups.Count).IsEqualTo(ExpectedGroupCount); } - /// - /// Verifies GroupByTypeSignature separates invocations with HasConversion difference. - /// + /// Verifies GroupByTypeSignature separates invocations with HasConversion difference. /// A task representing the asynchronous test operation. [Test] public async Task GroupByTypeSignature_DifferentHasConversion_SeparateGroups() @@ -63,23 +81,22 @@ public async Task GroupByTypeSignature_DifferentHasConversion_SeparateGroups() var inv2 = ModelFactory.CreateBindingInvocationInfo(hasConversion: true, methodName: "Bind"); var invocations = ImmutableArray.Create(inv1, inv2); + const int ExpectedGroupCount = 2; var groups = BindCodeGenerator.GroupByTypeSignature(invocations); - await Assert.That(groups.Count).IsEqualTo(2); + await Assert.That(groups.Count).IsEqualTo(ExpectedGroupCount); } - /// - /// Verifies FormatExtraArgs returns empty string when no conversion or scheduler. - /// + /// Verifies FormatExtraArgs returns empty string when no conversion or scheduler. /// A task representing the asynchronous test operation. [Test] public async Task FormatExtraArgs_NoConversionNoScheduler_ReturnsEmpty() { var group = new BindCodeGenerator.BindingTypeGroup( - "global::TestApp.VM", - "global::TestApp.View", - "global::System.String", - "global::System.String", + VMTypeName, + ViewTypeName, + StringTypeName, + StringTypeName, false, false, []); @@ -89,96 +106,86 @@ public async Task FormatExtraArgs_NoConversionNoScheduler_ReturnsEmpty() await Assert.That(result).IsEqualTo(string.Empty); } - /// - /// Verifies FormatExtraArgs includes converter args when HasConversion is true. - /// + /// Verifies FormatExtraArgs includes converter args when HasConversion is true. /// A task representing the asynchronous test operation. [Test] public async Task FormatExtraArgs_WithConversion_IncludesConverterArgs() { var group = new BindCodeGenerator.BindingTypeGroup( - "global::TestApp.VM", - "global::TestApp.View", - "global::System.String", - "global::System.String", + VMTypeName, + ViewTypeName, + StringTypeName, + StringTypeName, true, false, []); var result = BindCodeGenerator.FormatExtraArgs(group); - await Assert.That(result).Contains("vmToViewConverter"); - await Assert.That(result).Contains("viewToVmConverter"); + await Assert.That(result).Contains(ViewModelToViewConverterName); + await Assert.That(result).Contains(ViewToViewModelConverterName); } - /// - /// Verifies FormatExtraArgs includes scheduler arg when HasScheduler is true. - /// + /// Verifies FormatExtraArgs includes scheduler arg when HasScheduler is true. /// A task representing the asynchronous test operation. [Test] public async Task FormatExtraArgs_WithScheduler_IncludesSchedulerArg() { var group = new BindCodeGenerator.BindingTypeGroup( - "global::TestApp.VM", - "global::TestApp.View", - "global::System.String", - "global::System.String", + VMTypeName, + ViewTypeName, + StringTypeName, + StringTypeName, false, true, []); var result = BindCodeGenerator.FormatExtraArgs(group); - await Assert.That(result).Contains("scheduler"); + await Assert.That(result).Contains(SchedulerName); } - /// - /// Verifies FormatExtraArgs includes both converter and scheduler when both are true. - /// + /// Verifies FormatExtraArgs includes both converter and scheduler when both are true. /// A task representing the asynchronous test operation. [Test] public async Task FormatExtraArgs_WithConversionAndScheduler_IncludesBoth() { var group = new BindCodeGenerator.BindingTypeGroup( - "global::TestApp.VM", - "global::TestApp.View", - "global::System.String", - "global::System.String", + VMTypeName, + ViewTypeName, + StringTypeName, + StringTypeName, true, true, []); var result = BindCodeGenerator.FormatExtraArgs(group); - await Assert.That(result).Contains("vmToViewConverter"); - await Assert.That(result).Contains("scheduler"); + await Assert.That(result).Contains(ViewModelToViewConverterName); + await Assert.That(result).Contains(SchedulerName); } - /// - /// Verifies FormatReturnType produces expected IReactiveBinding type. - /// + /// Verifies FormatReturnType produces expected IReactiveBinding type. /// A task representing the asynchronous test operation. [Test] public async Task FormatReturnType_ReturnsIReactiveBindingType() { var group = new BindCodeGenerator.BindingTypeGroup( - "global::TestApp.VM", - "global::TestApp.View", - "global::System.String", - "global::System.String", + VMTypeName, + ViewTypeName, + StringTypeName, + StringTypeName, false, false, []); var result = BindCodeGenerator.FormatReturnType(group, false); - await Assert.That(result).Contains("IReactiveBinding"); - await Assert.That(result).Contains("global::TestApp.View"); + await Assert.That(result).Contains(IReactiveBindingName); + await Assert.That(result).Contains(ViewTypeName); } - /// - /// Verifies FormatMethodReturnType produces expected IReactiveBinding type for invocation. - /// + /// Verifies FormatMethodReturnType produces expected IReactiveBinding type for invocation. /// A task representing the asynchronous test operation. [Test] public async Task FormatMethodReturnType_ReturnsIReactiveBindingType() @@ -187,13 +194,11 @@ public async Task FormatMethodReturnType_ReturnsIReactiveBindingType() var result = BindCodeGenerator.FormatMethodReturnType(inv, false); - await Assert.That(result).Contains("IReactiveBinding"); - await Assert.That(result).Contains("global::TestApp.MyView"); + await Assert.That(result).Contains(IReactiveBindingName); + await Assert.That(result).Contains(MyViewTypeName); } - /// - /// Verifies FormatExtraMethodParams returns empty when no conversion or scheduler. - /// + /// Verifies FormatExtraMethodParams returns empty when no conversion or scheduler. /// A task representing the asynchronous test operation. [Test] public async Task FormatExtraMethodParams_NoConversionNoScheduler_ReturnsEmpty() @@ -208,9 +213,7 @@ public async Task FormatExtraMethodParams_NoConversionNoScheduler_ReturnsEmpty() await Assert.That(result).IsEqualTo(string.Empty); } - /// - /// Verifies FormatExtraMethodParams includes Func types when HasConversion is true. - /// + /// Verifies FormatExtraMethodParams includes Func types when HasConversion is true. /// A task representing the asynchronous test operation. [Test] public async Task FormatExtraMethodParams_WithConversion_IncludesFuncParams() @@ -220,13 +223,11 @@ public async Task FormatExtraMethodParams_WithConversion_IncludesFuncParams() var result = BindCodeGenerator.FormatExtraMethodParams(inv); await Assert.That(result).Contains("global::System.Func<"); - await Assert.That(result).Contains("vmToViewConverter"); - await Assert.That(result).Contains("viewToVmConverter"); + await Assert.That(result).Contains(ViewModelToViewConverterName); + await Assert.That(result).Contains(ViewToViewModelConverterName); } - /// - /// Verifies FormatExtraMethodParams includes IScheduler when HasScheduler is true. - /// + /// Verifies FormatExtraMethodParams includes IScheduler when HasScheduler is true. /// A task representing the asynchronous test operation. [Test] public async Task FormatExtraMethodParams_WithScheduler_IncludesSchedulerParam() @@ -236,12 +237,10 @@ public async Task FormatExtraMethodParams_WithScheduler_IncludesSchedulerParam() var result = BindCodeGenerator.FormatExtraMethodParams(inv); await Assert.That(result).Contains("IScheduler"); - await Assert.That(result).Contains("scheduler"); + await Assert.That(result).Contains(SchedulerName); } - /// - /// Verifies GenerateConcreteOverload dispatches to CallerArgExpr when supported. - /// + /// Verifies GenerateConcreteOverload dispatches to CallerArgExpr when supported. /// A task representing the asynchronous test operation. [Test] public async Task GenerateConcreteOverload_CallerArgExpr_GeneratesExpressionDispatch() @@ -250,9 +249,9 @@ public async Task GenerateConcreteOverload_CallerArgExpr_GeneratesExpressionDisp var inv = ModelFactory.CreateBindingInvocationInfo(methodName: "Bind"); var group = new BindCodeGenerator.BindingTypeGroup( "global::TestApp.MyViewModel", - "global::TestApp.MyView", - "global::System.String", - "global::System.String", + MyViewTypeName, + StringTypeName, + StringTypeName, false, false, [inv]); @@ -264,9 +263,7 @@ public async Task GenerateConcreteOverload_CallerArgExpr_GeneratesExpressionDisp await Assert.That(result).Contains("__Bind_"); } - /// - /// Verifies GenerateConcreteOverload dispatches to CallerFilePath when not supported. - /// + /// Verifies GenerateConcreteOverload dispatches to CallerFilePath when not supported. /// A task representing the asynchronous test operation. [Test] public async Task GenerateConcreteOverload_CallerFilePath_GeneratesFilePathDispatch() @@ -275,9 +272,9 @@ public async Task GenerateConcreteOverload_CallerFilePath_GeneratesFilePathDispa var inv = ModelFactory.CreateBindingInvocationInfo(methodName: "Bind"); var group = new BindCodeGenerator.BindingTypeGroup( "global::TestApp.MyViewModel", - "global::TestApp.MyView", - "global::System.String", - "global::System.String", + MyViewTypeName, + StringTypeName, + StringTypeName, false, false, [inv]); @@ -289,9 +286,7 @@ public async Task GenerateConcreteOverload_CallerFilePath_GeneratesFilePathDispa await Assert.That(result).Contains("callerLineNumber"); } - /// - /// Verifies GenerateBindMethod generates two-way binding with inline PropertyObservable and view-first parameter ordering. - /// + /// Verifies GenerateBindMethod generates two-way binding with inline PropertyObservable and view-first parameter ordering. /// A task representing the asynchronous test operation. [Test] public async Task GenerateBindMethod_StandardInvocation_GeneratesTwoWayBinding() @@ -300,7 +295,7 @@ public async Task GenerateBindMethod_StandardInvocation_GeneratesTwoWayBinding() var inv = ModelFactory.CreateBindingInvocationInfo(methodName: "Bind"); var sourceClassInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); var targetClassInfo = ModelFactory.CreateClassBindingInfo( - "global::TestApp.MyView", + MyViewTypeName, "MyView", implementsINPC: true); @@ -316,18 +311,16 @@ public async Task GenerateBindMethod_StandardInvocation_GeneratesTwoWayBinding() await Assert.That(result).Contains("Skip"); } - /// - /// Verifies AppendExtraParameters appends conversion parameters. - /// + /// Verifies AppendExtraParameters appends conversion parameters. /// A task representing the asynchronous test operation. [Test] public async Task AppendExtraParameters_WithConversion_AppendsConverterParams() { var sb = new StringBuilder(); var group = new BindCodeGenerator.BindingTypeGroup( - "global::TestApp.VM", - "global::TestApp.View", - "global::System.String", + VMTypeName, + ViewTypeName, + StringTypeName, "global::System.Int32", true, false, @@ -336,24 +329,22 @@ public async Task AppendExtraParameters_WithConversion_AppendsConverterParams() BindCodeGenerator.AppendExtraParameters(sb, group); var result = sb.ToString(); - await Assert.That(result).Contains("vmToViewConverter"); - await Assert.That(result).Contains("viewToVmConverter"); + await Assert.That(result).Contains(ViewModelToViewConverterName); + await Assert.That(result).Contains(ViewToViewModelConverterName); await Assert.That(result).Contains("global::System.Func"); } - /// - /// Verifies AppendExtraParameters appends scheduler parameter. - /// + /// Verifies AppendExtraParameters appends scheduler parameter. /// A task representing the asynchronous test operation. [Test] public async Task AppendExtraParameters_WithScheduler_AppendsSchedulerParam() { var sb = new StringBuilder(); var group = new BindCodeGenerator.BindingTypeGroup( - "global::TestApp.VM", - "global::TestApp.View", - "global::System.String", - "global::System.String", + VMTypeName, + ViewTypeName, + StringTypeName, + StringTypeName, false, true, []); diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/BindCommandCodeGeneratorHelperTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/BindCommandCodeGeneratorHelperTests.cs index 52513b2..c42394b 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/BindCommandCodeGeneratorHelperTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/BindCommandCodeGeneratorHelperTests.cs @@ -11,14 +11,37 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests.CodeGeneration; -/// -/// Tests for helper methods and command binding plugins. -/// +/// Tests for helper methods and command binding plugins. public class BindCommandCodeGeneratorHelperTests { - /// - /// Verifies CommandPropertyBindingPlugin.CanHandle returns true when HasCommandProperty is true. - /// + /// The Click name these tests generate against. + private const string ClickName = "Click"; + + /// The fully qualified name of the String type used by these tests. + private const string StringTypeName = "global::System.String"; + + /// The IObservable<global::System.String> withParameter fragment these tests expect in the generated source. + private const string IObservableGlobalSystemStringWithParameterFragment = "IObservable withParameter"; + + /// The Param name these tests generate against. + private const string ParamName = "Param"; + + /// The TESTSUFFIX name these tests generate against. + private const string TESTSUFFIXName = "TESTSUFFIX"; + + /// The view.SaveButton name these tests generate against. + private const string ViewSaveButtonName = "view.SaveButton"; + + /// The view.SaveButton.Click += __Handler fragment these tests expect in the generated source. + private const string ViewSaveButtonClickHandlerFragment = "view.SaveButton.Click += __Handler"; + + /// The view.SaveButton.Command = cmd fragment these tests expect in the generated source. + private const string ViewSaveButtonCommandCmdFragment = "view.SaveButton.Command = cmd"; + + /// The Volatile name these tests generate against. + private const string VolatileName = "Volatile"; + + /// Verifies CommandPropertyBindingPlugin.CanHandle returns true when HasCommandProperty is true. /// A task representing the asynchronous test operation. [Test] public async Task CommandPropertyPlugin_CanHandle_WithCommandProperty_ReturnsTrue() @@ -31,14 +54,12 @@ public async Task CommandPropertyPlugin_CanHandle_WithCommandProperty_ReturnsTru await Assert.That(result).IsTrue(); } - /// - /// Verifies CommandPropertyBindingPlugin.CanHandle returns false when HasCommandProperty is false. - /// + /// Verifies CommandPropertyBindingPlugin.CanHandle returns false when HasCommandProperty is false. /// A task representing the asynchronous test operation. [Test] public async Task CommandPropertyPlugin_CanHandle_WithoutCommandProperty_ReturnsFalse() { - var inv = ModelFactory.CreateBindCommandInvocationInfo(hasCommandProperty: false); + var inv = ModelFactory.CreateBindCommandInvocationInfo(); var plugin = new CommandPropertyBindingPlugin(); var result = plugin.CanHandle(inv); @@ -46,9 +67,7 @@ public async Task CommandPropertyPlugin_CanHandle_WithoutCommandProperty_Returns await Assert.That(result).IsFalse(); } - /// - /// Verifies CommandPropertyBindingPlugin emits Command+CommandParameter+observable parameter code. - /// + /// Verifies CommandPropertyBindingPlugin emits Command+CommandParameter+observable parameter code. /// A task representing the asynchronous test operation. [Test] public async Task CommandPropertyPlugin_EmitBinding_ObservableParam_EmitsVolatilePattern() @@ -56,76 +75,69 @@ public async Task CommandPropertyPlugin_EmitBinding_ObservableParam_EmitsVolatil var sb = new StringBuilder(); var inv = ModelFactory.CreateBindCommandInvocationInfo( hasObservableParameter: true, - parameterTypeFullName: "global::System.String", + parameterTypeFullName: StringTypeName, hasCommandProperty: true, hasCommandParameterProperty: true); var plugin = new CommandPropertyBindingPlugin(); - plugin.EmitBinding(sb, inv, "view.SaveButton", false); + plugin.EmitBinding(sb, inv, ViewSaveButtonName, false); var result = sb.ToString(); await Assert.That(result).Contains("Volatile.Write(ref __latestParam, p)"); - await Assert.That(result).Contains("view.SaveButton.Command = cmd"); + await Assert.That(result).Contains(ViewSaveButtonCommandCmdFragment); await Assert.That(result).Contains("view.SaveButton.CommandParameter = param"); await Assert.That(result).Contains("CompositeDisposable2"); } - /// - /// Verifies CommandPropertyBindingPlugin emits Command+CommandParameter+expression parameter code. - /// + /// Verifies CommandPropertyBindingPlugin emits Command+CommandParameter+expression parameter code. /// A task representing the asynchronous test operation. [Test] public async Task CommandPropertyPlugin_EmitBinding_ExpressionParam_EmitsDirectAccess() { var paramPath = new EquatableArray( - [ModelFactory.CreatePropertyPathSegment("Param", "global::System.String", "global::TestApp.MyViewModel")]); + [ModelFactory.CreatePropertyPathSegment(ParamName)]); var sb = new StringBuilder(); var inv = ModelFactory.CreateBindCommandInvocationInfo( hasExpressionParameter: true, - parameterTypeFullName: "global::System.String", + parameterTypeFullName: StringTypeName, parameterPropertyPath: paramPath, hasCommandProperty: true, hasCommandParameterProperty: true); var plugin = new CommandPropertyBindingPlugin(); - plugin.EmitBinding(sb, inv, "view.SaveButton", false); + plugin.EmitBinding(sb, inv, ViewSaveButtonName, false); var result = sb.ToString(); - await Assert.That(result).Contains("view.SaveButton.Command = cmd"); + await Assert.That(result).Contains(ViewSaveButtonCommandCmdFragment); await Assert.That(result).Contains("view.SaveButton.CommandParameter = viewModel.Param"); - await Assert.That(result).DoesNotContain("Volatile"); + await Assert.That(result).DoesNotContain(VolatileName); } - /// - /// Verifies CommandPropertyBindingPlugin emits Command-only code when no parameter. - /// + /// Verifies CommandPropertyBindingPlugin emits Command-only code when no parameter. /// A task representing the asynchronous test operation. [Test] public async Task CommandPropertyPlugin_EmitBinding_NoParam_EmitsCommandOnly() { var sb = new StringBuilder(); var inv = ModelFactory.CreateBindCommandInvocationInfo( - hasCommandProperty: true, - hasCommandParameterProperty: false); + hasCommandProperty: true); var plugin = new CommandPropertyBindingPlugin(); - plugin.EmitBinding(sb, inv, "view.SaveButton", false); + plugin.EmitBinding(sb, inv, ViewSaveButtonName, false); var result = sb.ToString(); - await Assert.That(result).Contains("view.SaveButton.Command = cmd"); + await Assert.That(result).Contains(ViewSaveButtonCommandCmdFragment); await Assert.That(result).DoesNotContain("CommandParameter"); - await Assert.That(result).DoesNotContain("Volatile"); + await Assert.That(result).DoesNotContain(VolatileName); } - /// - /// Verifies EventEnabledBindingPlugin.CanHandle returns true when event and Enabled property exist. - /// + /// Verifies EventEnabledBindingPlugin.CanHandle returns true when event and Enabled property exist. /// A task representing the asynchronous test operation. [Test] public async Task EventEnabledPlugin_CanHandle_WithEventAndEnabled_ReturnsTrue() { var inv = ModelFactory.CreateBindCommandInvocationInfo( - resolvedEventName: "Click", + resolvedEventName: ClickName, hasEnabledProperty: true); var plugin = new EventEnabledBindingPlugin(); @@ -134,9 +146,7 @@ public async Task EventEnabledPlugin_CanHandle_WithEventAndEnabled_ReturnsTrue() await Assert.That(result).IsTrue(); } - /// - /// Verifies EventEnabledBindingPlugin.CanHandle returns false when no event is resolved. - /// + /// Verifies EventEnabledBindingPlugin.CanHandle returns false when no event is resolved. /// A task representing the asynchronous test operation. [Test] public async Task EventEnabledPlugin_CanHandle_WithoutEvent_ReturnsFalse() @@ -151,16 +161,12 @@ public async Task EventEnabledPlugin_CanHandle_WithoutEvent_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies EventEnabledBindingPlugin.CanHandle returns false when no Enabled property. - /// + /// Verifies EventEnabledBindingPlugin.CanHandle returns false when no Enabled property. /// A task representing the asynchronous test operation. [Test] public async Task EventEnabledPlugin_CanHandle_WithoutEnabled_ReturnsFalse() { - var inv = ModelFactory.CreateBindCommandInvocationInfo( - resolvedEventName: "Click", - hasEnabledProperty: false); + var inv = ModelFactory.CreateBindCommandInvocationInfo(); var plugin = new EventEnabledBindingPlugin(); var result = plugin.CanHandle(inv); @@ -168,9 +174,7 @@ public async Task EventEnabledPlugin_CanHandle_WithoutEnabled_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies EventEnabledBindingPlugin emits event+Enabled with observable parameter. - /// + /// Verifies EventEnabledBindingPlugin emits event+Enabled with observable parameter. /// A task representing the asynchronous test operation. [Test] public async Task EventEnabledPlugin_EmitBinding_ObservableParam_EmitsCanExecuteSync() @@ -178,96 +182,88 @@ public async Task EventEnabledPlugin_EmitBinding_ObservableParam_EmitsCanExecute var sb = new StringBuilder(); var inv = ModelFactory.CreateBindCommandInvocationInfo( hasObservableParameter: true, - parameterTypeFullName: "global::System.String", - resolvedEventName: "Click", + parameterTypeFullName: StringTypeName, + resolvedEventName: ClickName, hasEnabledProperty: true); var plugin = new EventEnabledBindingPlugin(); - plugin.EmitBinding(sb, inv, "view.SaveButton", false); + plugin.EmitBinding(sb, inv, ViewSaveButtonName, false); var result = sb.ToString(); await Assert.That(result).Contains("view.SaveButton.Enabled = false"); await Assert.That(result).Contains("view.SaveButton.Enabled = cmd.CanExecute(param)"); await Assert.That(result).Contains("cmd.CanExecuteChanged += __canExecHandler"); - await Assert.That(result).Contains("view.SaveButton.Click += __Handler"); + await Assert.That(result).Contains(ViewSaveButtonClickHandlerFragment); await Assert.That(result).Contains("Volatile.Read(ref __latestParam)"); } - /// - /// Verifies EventEnabledBindingPlugin emits event+Enabled with expression parameter. - /// + /// Verifies EventEnabledBindingPlugin emits event+Enabled with expression parameter. /// A task representing the asynchronous test operation. [Test] public async Task EventEnabledPlugin_EmitBinding_ExpressionParam_EmitsDirectPropertyAccess() { var paramPath = new EquatableArray( - [ModelFactory.CreatePropertyPathSegment("Param", "global::System.String", "global::TestApp.MyViewModel")]); + [ModelFactory.CreatePropertyPathSegment(ParamName)]); var sb = new StringBuilder(); var inv = ModelFactory.CreateBindCommandInvocationInfo( hasExpressionParameter: true, - parameterTypeFullName: "global::System.String", + parameterTypeFullName: StringTypeName, parameterPropertyPath: paramPath, - resolvedEventName: "Click", + resolvedEventName: ClickName, hasEnabledProperty: true); var plugin = new EventEnabledBindingPlugin(); - plugin.EmitBinding(sb, inv, "view.SaveButton", false); + plugin.EmitBinding(sb, inv, ViewSaveButtonName, false); var result = sb.ToString(); await Assert.That(result).Contains("view.SaveButton.Enabled = cmd.CanExecute(viewModel.Param)"); - await Assert.That(result).Contains("view.SaveButton.Click += __Handler"); - await Assert.That(result).DoesNotContain("Volatile"); + await Assert.That(result).Contains(ViewSaveButtonClickHandlerFragment); + await Assert.That(result).DoesNotContain(VolatileName); } - /// - /// Verifies EventEnabledBindingPlugin emits event+Enabled with no parameter. - /// + /// Verifies EventEnabledBindingPlugin emits event+Enabled with no parameter. /// A task representing the asynchronous test operation. [Test] public async Task EventEnabledPlugin_EmitBinding_NoParam_EmitsNullParam() { var sb = new StringBuilder(); var inv = ModelFactory.CreateBindCommandInvocationInfo( - resolvedEventName: "Click", + resolvedEventName: ClickName, hasEnabledProperty: true); var plugin = new EventEnabledBindingPlugin(); - plugin.EmitBinding(sb, inv, "view.SaveButton", false); + plugin.EmitBinding(sb, inv, ViewSaveButtonName, false); var result = sb.ToString(); await Assert.That(result).Contains("view.SaveButton.Enabled = cmd.CanExecute(null)"); await Assert.That(result).Contains("cmd.Execute(null)"); - await Assert.That(result).Contains("view.SaveButton.Click += __Handler"); + await Assert.That(result).Contains(ViewSaveButtonClickHandlerFragment); } - /// - /// Verifies EventEnabledBindingPlugin uses fallback EventArgs type when null. - /// + /// Verifies EventEnabledBindingPlugin uses fallback EventArgs type when null. /// A task representing the asynchronous test operation. [Test] public async Task EventEnabledPlugin_EmitBinding_NullEventArgsType_UsesFallback() { var sb = new StringBuilder(); var inv = ModelFactory.CreateBindCommandInvocationInfo( - resolvedEventName: "Click", + resolvedEventName: ClickName, resolvedEventArgsTypeFullName: null, hasEnabledProperty: true); var plugin = new EventEnabledBindingPlugin(); - plugin.EmitBinding(sb, inv, "view.SaveButton", false); + plugin.EmitBinding(sb, inv, ViewSaveButtonName, false); var result = sb.ToString(); await Assert.That(result).Contains("global::System.EventArgs"); } - /// - /// Verifies DefaultEventBindingPlugin.CanHandle returns true when event is resolved. - /// + /// Verifies DefaultEventBindingPlugin.CanHandle returns true when event is resolved. /// A task representing the asynchronous test operation. [Test] public async Task DefaultEventPlugin_CanHandle_WithEvent_ReturnsTrue() { - var inv = ModelFactory.CreateBindCommandInvocationInfo(resolvedEventName: "Click"); + var inv = ModelFactory.CreateBindCommandInvocationInfo(); var plugin = new DefaultEventBindingPlugin(); var result = plugin.CanHandle(inv); @@ -275,9 +271,7 @@ public async Task DefaultEventPlugin_CanHandle_WithEvent_ReturnsTrue() await Assert.That(result).IsTrue(); } - /// - /// Verifies DefaultEventBindingPlugin.CanHandle returns false when no event. - /// + /// Verifies DefaultEventBindingPlugin.CanHandle returns false when no event. /// A task representing the asynchronous test operation. [Test] public async Task DefaultEventPlugin_CanHandle_WithoutEvent_ReturnsFalse() @@ -290,51 +284,46 @@ public async Task DefaultEventPlugin_CanHandle_WithoutEvent_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies DefaultEventBindingPlugin.EmitBinding uses fallback EventArgs when ResolvedEventArgsTypeFullName is null. - /// + /// Verifies DefaultEventBindingPlugin.EmitBinding uses fallback EventArgs when ResolvedEventArgsTypeFullName is null. /// A task representing the asynchronous test operation. [Test] public async Task DefaultEventPlugin_EmitBinding_NullEventArgsType_UsesFallback() { var sb = new StringBuilder(); var inv = ModelFactory.CreateBindCommandInvocationInfo( - resolvedEventName: "Click", + resolvedEventName: ClickName, resolvedEventArgsTypeFullName: null); var plugin = new DefaultEventBindingPlugin(); - plugin.EmitBinding(sb, inv, "view.SaveButton", false); + plugin.EmitBinding(sb, inv, ViewSaveButtonName, false); var result = sb.ToString(); await Assert.That(result).Contains("global::System.EventArgs"); } - /// - /// Verifies DefaultEventBindingPlugin.EmitBinding uses specific EventArgs when provided. - /// + /// Verifies DefaultEventBindingPlugin.EmitBinding uses specific EventArgs when provided. /// A task representing the asynchronous test operation. [Test] public async Task DefaultEventPlugin_EmitBinding_WithEventArgsType_UsesSpecificType() { var sb = new StringBuilder(); var inv = ModelFactory.CreateBindCommandInvocationInfo( - resolvedEventName: "Click", + resolvedEventName: ClickName, resolvedEventArgsTypeFullName: "global::System.Windows.RoutedEventArgs"); var plugin = new DefaultEventBindingPlugin(); - plugin.EmitBinding(sb, inv, "view.SaveButton", false); + plugin.EmitBinding(sb, inv, ViewSaveButtonName, false); var result = sb.ToString(); await Assert.That(result).Contains("global::System.Windows.RoutedEventArgs"); } - /// - /// Verifies GroupByTypeSignature groups BindCommand invocations with the same type signature. - /// + /// Verifies GroupByTypeSignature groups BindCommand invocations with the same type signature. /// A task representing the asynchronous test operation. [Test] public async Task GroupByTypeSignature_SameSignature_GroupedTogether() { + const int ExpectedInvocationCount = 2; var inv1 = ModelFactory.CreateBindCommandInvocationInfo(callerLineNumber: 10); var inv2 = ModelFactory.CreateBindCommandInvocationInfo(callerLineNumber: 20); var invocations = ImmutableArray.Create(inv1, inv2); @@ -342,28 +331,25 @@ public async Task GroupByTypeSignature_SameSignature_GroupedTogether() var groups = BindCommandCodeGenerator.GroupByTypeSignature(invocations); await Assert.That(groups.Count).IsEqualTo(1); - await Assert.That(groups[0].Invocations.Length).IsEqualTo(2); + await Assert.That(groups[0].Invocations.Length).IsEqualTo(ExpectedInvocationCount); } - /// - /// Verifies GroupByTypeSignature separates invocations with different view types. - /// + /// Verifies GroupByTypeSignature separates invocations with different view types. /// A task representing the asynchronous test operation. [Test] public async Task GroupByTypeSignature_DifferentViewTypes_SeparateGroups() { + const int ExpectedGroupCount = 2; var inv1 = ModelFactory.CreateBindCommandInvocationInfo(viewTypeFullName: "global::TestApp.ViewA"); var inv2 = ModelFactory.CreateBindCommandInvocationInfo(viewTypeFullName: "global::TestApp.ViewB"); var invocations = ImmutableArray.Create(inv1, inv2); var groups = BindCommandCodeGenerator.GroupByTypeSignature(invocations); - await Assert.That(groups.Count).IsEqualTo(2); + await Assert.That(groups.Count).IsEqualTo(ExpectedGroupCount); } - /// - /// Verifies GenerateConcreteOverload generates CallerArgumentExpression dispatch. - /// + /// Verifies GenerateConcreteOverload generates CallerArgumentExpression dispatch. /// A task representing the asynchronous test operation. [Test] public async Task GenerateConcreteOverload_CallerArgExpr_GeneratesExpressionDispatch() @@ -387,9 +373,7 @@ public async Task GenerateConcreteOverload_CallerArgExpr_GeneratesExpressionDisp await Assert.That(result).Contains("__BindCommand_"); } - /// - /// Verifies GenerateConcreteOverload generates CallerFilePath dispatch. - /// + /// Verifies GenerateConcreteOverload generates CallerFilePath dispatch. /// A task representing the asynchronous test operation. [Test] public async Task GenerateConcreteOverload_CallerFilePath_GeneratesFilePathDispatch() @@ -413,9 +397,7 @@ public async Task GenerateConcreteOverload_CallerFilePath_GeneratesFilePathDispa await Assert.That(result).Contains("callerLineNumber"); } - /// - /// Verifies GenerateConcreteOverload with observable parameter includes withParameter. - /// + /// Verifies GenerateConcreteOverload with observable parameter includes withParameter. /// A task representing the asynchronous test operation. [Test] public async Task GenerateCallerArgExprOverload_WithObservableParam_IncludesWithParameter() @@ -423,7 +405,7 @@ public async Task GenerateCallerArgExprOverload_WithObservableParam_IncludesWith var sb = new StringBuilder(); var inv = ModelFactory.CreateBindCommandInvocationInfo( hasObservableParameter: true, - parameterTypeFullName: "global::System.String"); + parameterTypeFullName: StringTypeName); var group = new BindCommandCodeGenerator.BindCommandTypeGroup( inv.ViewTypeFullName, inv.ViewModelTypeFullName, @@ -431,19 +413,17 @@ public async Task GenerateCallerArgExprOverload_WithObservableParam_IncludesWith inv.ControlTypeFullName, true, false, - "global::System.String", + StringTypeName, [inv]); BindCommandCodeGenerator.GenerateCallerArgExprOverload(sb, group, false); var result = sb.ToString(); - await Assert.That(result).Contains("IObservable withParameter"); + await Assert.That(result).Contains(IObservableGlobalSystemStringWithParameterFragment); await Assert.That(result).Contains(", withParameter)"); } - /// - /// Verifies GenerateConcreteOverload with expression parameter includes withParameter expression. - /// + /// Verifies GenerateConcreteOverload with expression parameter includes withParameter expression. /// A task representing the asynchronous test operation. [Test] public async Task GenerateCallerArgExprOverload_WithExpressionParam_IncludesWithParameterExpr() @@ -451,7 +431,7 @@ public async Task GenerateCallerArgExprOverload_WithExpressionParam_IncludesWith var sb = new StringBuilder(); var inv = ModelFactory.CreateBindCommandInvocationInfo( hasExpressionParameter: true, - parameterTypeFullName: "global::System.String"); + parameterTypeFullName: StringTypeName); var group = new BindCommandCodeGenerator.BindCommandTypeGroup( inv.ViewTypeFullName, inv.ViewModelTypeFullName, @@ -459,7 +439,7 @@ public async Task GenerateCallerArgExprOverload_WithExpressionParam_IncludesWith inv.ControlTypeFullName, false, true, - "global::System.String", + StringTypeName, [inv]); BindCommandCodeGenerator.GenerateCallerArgExprOverload(sb, group, false); @@ -469,9 +449,7 @@ public async Task GenerateCallerArgExprOverload_WithExpressionParam_IncludesWith await Assert.That(result).Contains("withParameterExpression"); } - /// - /// Verifies CallerFilePath overload with observable parameter. - /// + /// Verifies CallerFilePath overload with observable parameter. /// A task representing the asynchronous test operation. [Test] public async Task GenerateCallerFilePathOverload_WithObservableParam_IncludesWithParameter() @@ -479,7 +457,7 @@ public async Task GenerateCallerFilePathOverload_WithObservableParam_IncludesWit var sb = new StringBuilder(); var inv = ModelFactory.CreateBindCommandInvocationInfo( hasObservableParameter: true, - parameterTypeFullName: "global::System.String"); + parameterTypeFullName: StringTypeName); var group = new BindCommandCodeGenerator.BindCommandTypeGroup( inv.ViewTypeFullName, inv.ViewModelTypeFullName, @@ -487,18 +465,16 @@ public async Task GenerateCallerFilePathOverload_WithObservableParam_IncludesWit inv.ControlTypeFullName, true, false, - "global::System.String", + StringTypeName, [inv]); BindCommandCodeGenerator.GenerateCallerFilePathOverload(sb, group, false); var result = sb.ToString(); - await Assert.That(result).Contains("IObservable withParameter"); + await Assert.That(result).Contains(IObservableGlobalSystemStringWithParameterFragment); } - /// - /// Verifies CallerFilePath overload with expression parameter. - /// + /// Verifies CallerFilePath overload with expression parameter. /// A task representing the asynchronous test operation. [Test] public async Task GenerateCallerFilePathOverload_WithExpressionParam_IncludesWithParameter() @@ -506,7 +482,7 @@ public async Task GenerateCallerFilePathOverload_WithExpressionParam_IncludesWit var sb = new StringBuilder(); var inv = ModelFactory.CreateBindCommandInvocationInfo( hasExpressionParameter: true, - parameterTypeFullName: "global::System.String"); + parameterTypeFullName: StringTypeName); var group = new BindCommandCodeGenerator.BindCommandTypeGroup( inv.ViewTypeFullName, inv.ViewModelTypeFullName, @@ -514,7 +490,7 @@ public async Task GenerateCallerFilePathOverload_WithExpressionParam_IncludesWit inv.ControlTypeFullName, false, true, - "global::System.String", + StringTypeName, [inv]); BindCommandCodeGenerator.GenerateCallerFilePathOverload(sb, group, false); @@ -523,41 +499,36 @@ public async Task GenerateCallerFilePathOverload_WithExpressionParam_IncludesWit await Assert.That(result).Contains("Expression - /// Verifies GenerateBindCommandMethod with CommandProperty plugin path. - /// + /// Verifies GenerateBindCommandMethod with CommandProperty plugin path. /// A task representing the asynchronous test operation. [Test] public async Task GenerateBindCommandMethod_CommandPropertyPlugin_EmitsCommandBinding() { var sb = new StringBuilder(); var inv = ModelFactory.CreateBindCommandInvocationInfo( - hasCommandProperty: true, - hasCommandParameterProperty: false); - var vmClassInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); + hasCommandProperty: true); + var viewModelClassInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); - BindCommandCodeGenerator.GenerateBindCommandMethod(sb, inv, vmClassInfo, "TESTSUFFIX", false); + BindCommandCodeGenerator.GenerateBindCommandMethod(sb, inv, viewModelClassInfo, TESTSUFFIXName, false); var result = sb.ToString(); await Assert.That(result).Contains("__BindCommand_TESTSUFFIX"); await Assert.That(result).Contains(".Command = cmd"); } - /// - /// Verifies GenerateBindCommandMethod with EventEnabled plugin path. - /// + /// Verifies GenerateBindCommandMethod with EventEnabled plugin path. /// A task representing the asynchronous test operation. [Test] public async Task GenerateBindCommandMethod_EventEnabledPlugin_EmitsEnabledSync() { var sb = new StringBuilder(); var inv = ModelFactory.CreateBindCommandInvocationInfo( - resolvedEventName: "Click", + resolvedEventName: ClickName, hasCommandProperty: false, hasEnabledProperty: true); - var vmClassInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); + var viewModelClassInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); - BindCommandCodeGenerator.GenerateBindCommandMethod(sb, inv, vmClassInfo, "TESTSUFFIX", false); + BindCommandCodeGenerator.GenerateBindCommandMethod(sb, inv, viewModelClassInfo, TESTSUFFIXName, false); var result = sb.ToString(); await Assert.That(result).Contains("__BindCommand_TESTSUFFIX"); @@ -566,40 +537,35 @@ public async Task GenerateBindCommandMethod_EventEnabledPlugin_EmitsEnabledSync( await Assert.That(result).Contains("HasHigherAffinityPlugin"); } - /// - /// Verifies GenerateBindCommandMethod with no plugin match falls through to custom binder + throw. - /// + /// Verifies GenerateBindCommandMethod with no plugin match falls through to custom binder + throw. /// A task representing the asynchronous test operation. [Test] public async Task GenerateBindCommandMethod_NoPlugin_EmitsThrow() { var sb = new StringBuilder(); var inv = ModelFactory.CreateBindCommandInvocationInfo( - resolvedEventName: null, - hasCommandProperty: false, - hasEnabledProperty: false); - var vmClassInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); + resolvedEventName: null); + var viewModelClassInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); - BindCommandCodeGenerator.GenerateBindCommandMethod(sb, inv, vmClassInfo, "TESTSUFFIX", false); + BindCommandCodeGenerator.GenerateBindCommandMethod(sb, inv, viewModelClassInfo, TESTSUFFIXName, false); var result = sb.ToString(); await Assert.That(result).Contains("No bindable event found"); await Assert.That(result).Contains("HasHigherAffinityPlugin"); } - /// - /// Verifies EmitCommandAffinityCheck with observable parameter emits Select wrapper. - /// + /// Verifies EmitCommandAffinityCheck with observable parameter emits Select wrapper. /// A task representing the asynchronous test operation. [Test] public async Task EmitCommandAffinityCheck_ObservableParam_EmitsSelectWrapper() { + const int GeneratedAffinity = 5; var sb = new StringBuilder(); var inv = ModelFactory.CreateBindCommandInvocationInfo( hasObservableParameter: true, - parameterTypeFullName: "global::System.String"); + parameterTypeFullName: StringTypeName); - BindCommandCodeGenerator.EmitCommandAffinityCheck(sb, inv, "view.SaveButton", 5, true); + BindCommandCodeGenerator.EmitCommandAffinityCheck(sb, inv, ViewSaveButtonName, GeneratedAffinity, true); var result = sb.ToString(); await Assert.That(result).Contains("SelectObservable"); @@ -607,31 +573,28 @@ public async Task EmitCommandAffinityCheck_ObservableParam_EmitsSelectWrapper() await Assert.That(result).Contains("GetBinder(true)"); } - /// - /// Verifies EmitCommandAffinityCheck with expression parameter emits ReturnObservable. - /// + /// Verifies EmitCommandAffinityCheck with expression parameter emits ReturnObservable. /// A task representing the asynchronous test operation. [Test] public async Task EmitCommandAffinityCheck_ExpressionParam_EmitsReturnObservable() { + const int GeneratedAffinity = 3; var paramPath = new EquatableArray( - [ModelFactory.CreatePropertyPathSegment("Param", "global::System.String", "global::TestApp.MyViewModel")]); + [ModelFactory.CreatePropertyPathSegment(ParamName)]); var sb = new StringBuilder(); var inv = ModelFactory.CreateBindCommandInvocationInfo( hasExpressionParameter: true, - parameterTypeFullName: "global::System.String", + parameterTypeFullName: StringTypeName, parameterPropertyPath: paramPath); - BindCommandCodeGenerator.EmitCommandAffinityCheck(sb, inv, "view.SaveButton", 3, true); + BindCommandCodeGenerator.EmitCommandAffinityCheck(sb, inv, ViewSaveButtonName, GeneratedAffinity, true); var result = sb.ToString(); await Assert.That(result).Contains("ReturnObservable(viewModel.Param)"); await Assert.That(result).Contains("HasHigherAffinityPlugin(3, true)"); } - /// - /// Verifies EmitCommandAffinityCheck with no parameter emits EmptyObservable. - /// + /// Verifies EmitCommandAffinityCheck with no parameter emits EmptyObservable. /// A task representing the asynchronous test operation. [Test] public async Task EmitCommandAffinityCheck_NoParam_EmitsEmptyObservable() @@ -639,7 +602,7 @@ public async Task EmitCommandAffinityCheck_NoParam_EmitsEmptyObservable() var sb = new StringBuilder(); var inv = ModelFactory.CreateBindCommandInvocationInfo(); - BindCommandCodeGenerator.EmitCommandAffinityCheck(sb, inv, "view.SaveButton", -1, false); + BindCommandCodeGenerator.EmitCommandAffinityCheck(sb, inv, ViewSaveButtonName, -1, false); var result = sb.ToString(); await Assert.That(result).Contains("EmptyObservable.Instance"); @@ -647,34 +610,30 @@ public async Task EmitCommandAffinityCheck_NoParam_EmitsEmptyObservable() await Assert.That(result).Contains("GetBinder(false)"); } - /// - /// Verifies BuildParameterObservableExpression returns SelectObservable for observable parameter. - /// + /// Verifies BuildParameterObservableExpression returns SelectObservable for observable parameter. /// A task representing the asynchronous test operation. [Test] public async Task BuildParameterObservableExpression_ObservableParam_ReturnsSelectObservable() { var inv = ModelFactory.CreateBindCommandInvocationInfo( hasObservableParameter: true, - parameterTypeFullName: "global::System.String"); + parameterTypeFullName: StringTypeName); var result = BindCommandCodeGenerator.BuildParameterObservableExpression(inv); await Assert.That(result).Contains("SelectObservable"); } - /// - /// Verifies BuildParameterObservableExpression returns ReturnObservable for expression parameter. - /// + /// Verifies BuildParameterObservableExpression returns ReturnObservable for expression parameter. /// A task representing the asynchronous test operation. [Test] public async Task BuildParameterObservableExpression_ExpressionParam_ReturnsReturnObservable() { var paramPath = new EquatableArray( - [ModelFactory.CreatePropertyPathSegment("Param", "global::System.String", "global::TestApp.MyViewModel")]); + [ModelFactory.CreatePropertyPathSegment(ParamName)]); var inv = ModelFactory.CreateBindCommandInvocationInfo( hasExpressionParameter: true, - parameterTypeFullName: "global::System.String", + parameterTypeFullName: StringTypeName, parameterPropertyPath: paramPath); var result = BindCommandCodeGenerator.BuildParameterObservableExpression(inv); @@ -682,9 +641,7 @@ public async Task BuildParameterObservableExpression_ExpressionParam_ReturnsRetu await Assert.That(result).Contains("ReturnObservable(viewModel.Param)"); } - /// - /// Verifies BuildParameterObservableExpression returns EmptyObservable when no parameter. - /// + /// Verifies BuildParameterObservableExpression returns EmptyObservable when no parameter. /// A task representing the asynchronous test operation. [Test] public async Task BuildParameterObservableExpression_NoParam_ReturnsEmptyObservable() @@ -696,9 +653,7 @@ public async Task BuildParameterObservableExpression_NoParam_ReturnsEmptyObserva await Assert.That(result).Contains("EmptyObservable.Instance"); } - /// - /// Verifies Generate returns null when invocations are empty. - /// + /// Verifies Generate returns null when invocations are empty. /// A task representing the asynchronous test operation. [Test] public async Task Generate_EmptyInvocations_ReturnsNull() @@ -706,14 +661,12 @@ public async Task Generate_EmptyInvocations_ReturnsNull() var result = BindCommandCodeGenerator.Generate( [], [], - new LanguageFeatures(true, true, true)); + new(true, true, true)); await Assert.That(result).IsNull(); } - /// - /// Verifies Generate returns null when invocations are default. - /// + /// Verifies Generate returns null when invocations are default. /// A task representing the asynchronous test operation. [Test] public async Task Generate_DefaultInvocations_ReturnsNull() @@ -721,14 +674,12 @@ public async Task Generate_DefaultInvocations_ReturnsNull() var result = BindCommandCodeGenerator.Generate( default, [], - new LanguageFeatures(true, true, true)); + new(true, true, true)); await Assert.That(result).IsNull(); } - /// - /// Verifies GenerateBindCommandMethod with observable parameter generates correct method params. - /// + /// Verifies GenerateBindCommandMethod with observable parameter generates correct method params. /// A task representing the asynchronous test operation. [Test] public async Task GenerateBindCommandMethod_WithObservableParam_IncludesObservableParam() @@ -736,14 +687,13 @@ public async Task GenerateBindCommandMethod_WithObservableParam_IncludesObservab var sb = new StringBuilder(); var inv = ModelFactory.CreateBindCommandInvocationInfo( hasObservableParameter: true, - parameterTypeFullName: "global::System.String", - resolvedEventName: "Click"); - var vmClassInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); + parameterTypeFullName: StringTypeName); + var viewModelClassInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); - BindCommandCodeGenerator.GenerateBindCommandMethod(sb, inv, vmClassInfo, "TESTSUFFIX", false); + BindCommandCodeGenerator.GenerateBindCommandMethod(sb, inv, viewModelClassInfo, TESTSUFFIXName, false); var result = sb.ToString(); - await Assert.That(result).Contains("IObservable withParameter"); + await Assert.That(result).Contains(IObservableGlobalSystemStringWithParameterFragment); } /// @@ -759,13 +709,12 @@ public async Task GenerateBindCommandMethod_WithExpressionParam_ReadsParameterFr var sb = new StringBuilder(); var inv = ModelFactory.CreateBindCommandInvocationInfo( hasExpressionParameter: true, - parameterTypeFullName: "global::System.String", + parameterTypeFullName: StringTypeName, parameterPropertyPath: new EquatableArray( - [ModelFactory.CreatePropertyPathSegment("Param", "global::System.String", "global::TestApp.MyViewModel")]), - resolvedEventName: "Click"); - var vmClassInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); + [ModelFactory.CreatePropertyPathSegment(ParamName)])); + var viewModelClassInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); - BindCommandCodeGenerator.GenerateBindCommandMethod(sb, inv, vmClassInfo, "TESTSUFFIX", false); + BindCommandCodeGenerator.GenerateBindCommandMethod(sb, inv, viewModelClassInfo, TESTSUFFIXName, false); var result = sb.ToString(); await Assert.That(result).Contains("ReturnObservable"); @@ -775,7 +724,6 @@ public async Task GenerateBindCommandMethod_WithExpressionParam_ReadsParameterFr // ─────────────────────────────────────────────────────────────────────────── // Nullability annotations (C# 8+ targets emit nullable-aware syntax; C# 7.3 does not) // ─────────────────────────────────────────────────────────────────────────── - /// /// Verifies the DefaultEvent plugin emits a nullable handler sender parameter (object?) /// under nullable support, so the generated local function matches the EventHandler delegate. @@ -785,9 +733,9 @@ public async Task GenerateBindCommandMethod_WithExpressionParam_ReadsParameterFr public async Task DefaultEventPlugin_EmitBinding_SupportsNullable_EmitsNullableSender() { var sb = new StringBuilder(); - var inv = ModelFactory.CreateBindCommandInvocationInfo(resolvedEventName: "Click"); + var inv = ModelFactory.CreateBindCommandInvocationInfo(); - new DefaultEventBindingPlugin().EmitBinding(sb, inv, "view.SaveButton", true); + new DefaultEventBindingPlugin().EmitBinding(sb, inv, ViewSaveButtonName, true); var result = sb.ToString(); await Assert.That(result).Contains("void __Handler(object? sender,"); @@ -803,28 +751,26 @@ public async Task DefaultEventPlugin_EmitBinding_SupportsNullable_EmitsNullableS public async Task DefaultEventPlugin_EmitBinding_NoNullable_EmitsPlainSender() { var sb = new StringBuilder(); - var inv = ModelFactory.CreateBindCommandInvocationInfo(resolvedEventName: "Click"); + var inv = ModelFactory.CreateBindCommandInvocationInfo(); - new DefaultEventBindingPlugin().EmitBinding(sb, inv, "view.SaveButton", false); + new DefaultEventBindingPlugin().EmitBinding(sb, inv, ViewSaveButtonName, false); var result = sb.ToString(); await Assert.That(result).Contains("void __Handler(object sender,"); await Assert.That(result).DoesNotContain("object? sender"); } - /// - /// Verifies the EventEnabled plugin also emits a nullable handler sender under nullable support. - /// + /// Verifies the EventEnabled plugin also emits a nullable handler sender under nullable support. /// A task representing the asynchronous test operation. [Test] public async Task EventEnabledPlugin_EmitBinding_SupportsNullable_EmitsNullableSender() { var sb = new StringBuilder(); var inv = ModelFactory.CreateBindCommandInvocationInfo( - resolvedEventName: "Click", + resolvedEventName: ClickName, hasEnabledProperty: true); - new EventEnabledBindingPlugin().EmitBinding(sb, inv, "view.SaveButton", true); + new EventEnabledBindingPlugin().EmitBinding(sb, inv, ViewSaveButtonName, true); await Assert.That(sb.ToString()).Contains("void __Handler(object? sender,"); } @@ -841,12 +787,12 @@ public async Task CommandPropertyPlugin_EmitBinding_SupportsNullable_ReferencePa var sb = new StringBuilder(); var inv = ModelFactory.CreateBindCommandInvocationInfo( hasObservableParameter: true, - parameterTypeFullName: "global::System.String", + parameterTypeFullName: StringTypeName, parameterIsReferenceType: true, hasCommandProperty: true, hasCommandParameterProperty: true); - new CommandPropertyBindingPlugin().EmitBinding(sb, inv, "view.SaveButton", true); + new CommandPropertyBindingPlugin().EmitBinding(sb, inv, ViewSaveButtonName, true); await Assert.That(sb.ToString()).Contains("global::System.String? __latestParam = default;"); } @@ -868,7 +814,7 @@ public async Task CommandPropertyPlugin_EmitBinding_SupportsNullable_ValueParam_ hasCommandProperty: true, hasCommandParameterProperty: true); - new CommandPropertyBindingPlugin().EmitBinding(sb, inv, "view.SaveButton", true); + new CommandPropertyBindingPlugin().EmitBinding(sb, inv, ViewSaveButtonName, true); var result = sb.ToString(); await Assert.That(result).Contains("global::System.Int32 __latestParam = default;"); @@ -892,9 +838,7 @@ public async Task GenerateConcreteOverload_SupportsNullable_EmitsNullableToEvent await Assert.That(sb.ToString()).Contains("string? toEvent = null"); } - /// - /// Verifies the concrete BindCommand overload emits a non-nullable toEvent parameter on C# 7.3. - /// + /// Verifies the concrete BindCommand overload emits a non-nullable toEvent parameter on C# 7.3. /// A task representing the asynchronous test operation. [Test] public async Task GenerateConcreteOverload_NoNullable_EmitsPlainToEvent() @@ -921,15 +865,13 @@ public async Task Generate_SupportsNullable_EmitsNullableEnableDirective() var result = BindCommandCodeGenerator.Generate( [ModelFactory.CreateBindCommandInvocationInfo()], [], - new LanguageFeatures(true, true, true)); + new(true, true, true)); await Assert.That(result).IsNotNull(); await Assert.That(result!).Contains("#nullable enable"); } - /// - /// Verifies the full BindCommand generation omits the #nullable enable directive on C# 7.3. - /// + /// Verifies the full BindCommand generation omits the #nullable enable directive on C# 7.3. /// A task representing the asynchronous test operation. [Test] public async Task Generate_NoNullable_OmitsNullableEnableDirective() @@ -937,7 +879,7 @@ public async Task Generate_NoNullable_OmitsNullableEnableDirective() var result = BindCommandCodeGenerator.Generate( [ModelFactory.CreateBindCommandInvocationInfo()], [], - new LanguageFeatures(true, false, true)); + new(true, false, true)); await Assert.That(result).IsNotNull(); await Assert.That(result!).DoesNotContain("#nullable enable"); diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/BindOneWayCodeGeneratorHelperTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/BindOneWayCodeGeneratorHelperTests.cs index 88f7be4..3980133 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/BindOneWayCodeGeneratorHelperTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/BindOneWayCodeGeneratorHelperTests.cs @@ -10,18 +10,33 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests.CodeGeneration; -/// -/// Tests for helper methods. -/// +/// Tests for helper methods. public class BindOneWayCodeGeneratorHelperTests { - /// - /// Verifies GroupByTypeSignature groups invocations with the same type signature. - /// + /// The __BindOneWay_ local the generated code is expected to emit. + private const string BindOneWayLocal = "__BindOneWay_"; + + /// The conversionFunc name these tests generate against. + private const string ConversionFuncName = "conversionFunc"; + + /// The fully qualified name of the String type used by these tests. + private const string StringTypeName = "global::System.String"; + + /// The fully qualified name of the MyView type used by these tests. + private const string MyViewTypeName = "global::TestApp.MyView"; + + /// The fully qualified name of the MyViewModel type used by these tests. + private const string MyViewModelTypeName = "global::TestApp.MyViewModel"; + + /// The TEST00000000TEST name these tests generate against. + private const string TEST00000000TESTName = "TEST00000000TEST"; + + /// Verifies GroupByTypeSignature groups invocations with the same type signature. /// A task representing the asynchronous test operation. [Test] public async Task GroupByTypeSignature_SameSignature_GroupedTogether() { + const int ExpectedInvocationCount = 2; var inv1 = ModelFactory.CreateBindingInvocationInfo(callerLineNumber: 10); var inv2 = ModelFactory.CreateBindingInvocationInfo(callerLineNumber: 20); var invocations = ImmutableArray.Create(inv1, inv2); @@ -29,28 +44,25 @@ public async Task GroupByTypeSignature_SameSignature_GroupedTogether() var groups = BindOneWayCodeGenerator.GroupByTypeSignature(invocations); await Assert.That(groups.Count).IsEqualTo(1); - await Assert.That(groups[0].Invocations.Length).IsEqualTo(2); + await Assert.That(groups[0].Invocations.Length).IsEqualTo(ExpectedInvocationCount); } - /// - /// Verifies GroupByTypeSignature separates invocations with different source types. - /// + /// Verifies GroupByTypeSignature separates invocations with different source types. /// A task representing the asynchronous test operation. [Test] public async Task GroupByTypeSignature_DifferentSourceTypes_SeparateGroups() { + const int ExpectedGroupCount = 2; var inv1 = ModelFactory.CreateBindingInvocationInfo(sourceTypeFullName: "global::TestApp.ViewModelA"); var inv2 = ModelFactory.CreateBindingInvocationInfo(sourceTypeFullName: "global::TestApp.ViewModelB"); var invocations = ImmutableArray.Create(inv1, inv2); var groups = BindOneWayCodeGenerator.GroupByTypeSignature(invocations); - await Assert.That(groups.Count).IsEqualTo(2); + await Assert.That(groups.Count).IsEqualTo(ExpectedGroupCount); } - /// - /// Verifies GenerateConcreteOverload dispatches to CallerArgExpr when supported. - /// + /// Verifies GenerateConcreteOverload dispatches to CallerArgExpr when supported. /// A task representing the asynchronous test operation. [Test] public async Task GenerateConcreteOverload_CallerArgExprSupported_GeneratesCallerArgExprOverload() @@ -58,10 +70,10 @@ public async Task GenerateConcreteOverload_CallerArgExprSupported_GeneratesCalle var sb = new StringBuilder(); var inv = ModelFactory.CreateBindingInvocationInfo(); var group = new BindOneWayCodeGenerator.BindingTypeGroup( - "global::TestApp.MyViewModel", - "global::TestApp.MyView", - "global::System.String", - "global::System.String", + MyViewModelTypeName, + MyViewTypeName, + StringTypeName, + StringTypeName, false, false, [inv]); @@ -70,12 +82,10 @@ public async Task GenerateConcreteOverload_CallerArgExprSupported_GeneratesCalle var result = sb.ToString(); await Assert.That(result).Contains("CallerArgumentExpression"); - await Assert.That(result).Contains("__BindOneWay_"); + await Assert.That(result).Contains(BindOneWayLocal); } - /// - /// Verifies GenerateConcreteOverload dispatches to CallerFilePath when not supported. - /// + /// Verifies GenerateConcreteOverload dispatches to CallerFilePath when not supported. /// A task representing the asynchronous test operation. [Test] public async Task GenerateConcreteOverload_CallerArgExprNotSupported_GeneratesCallerFilePathOverload() @@ -83,10 +93,10 @@ public async Task GenerateConcreteOverload_CallerArgExprNotSupported_GeneratesCa var sb = new StringBuilder(); var inv = ModelFactory.CreateBindingInvocationInfo(); var group = new BindOneWayCodeGenerator.BindingTypeGroup( - "global::TestApp.MyViewModel", - "global::TestApp.MyView", - "global::System.String", - "global::System.String", + MyViewModelTypeName, + MyViewTypeName, + StringTypeName, + StringTypeName, false, false, [inv]); @@ -98,22 +108,18 @@ public async Task GenerateConcreteOverload_CallerArgExprNotSupported_GeneratesCa await Assert.That(result).Contains("callerLineNumber"); } - /// - /// Verifies GenerateCallerArgExprOverload generates dual expression dispatch. - /// + /// Verifies GenerateCallerArgExprOverload generates dual expression dispatch. /// A task representing the asynchronous test operation. [Test] public async Task GenerateCallerArgExprOverload_SingleInvocation_GeneratesDualExpressionDispatch() { var sb = new StringBuilder(); - var inv = ModelFactory.CreateBindingInvocationInfo( - sourceExpressionText: "x => x.Name", - targetExpressionText: "x => x.Text"); + var inv = ModelFactory.CreateBindingInvocationInfo(); var group = new BindOneWayCodeGenerator.BindingTypeGroup( - "global::TestApp.MyViewModel", - "global::TestApp.MyView", - "global::System.String", - "global::System.String", + MyViewModelTypeName, + MyViewTypeName, + StringTypeName, + StringTypeName, false, false, [inv]); @@ -123,25 +129,21 @@ public async Task GenerateCallerArgExprOverload_SingleInvocation_GeneratesDualEx var result = sb.ToString(); await Assert.That(result).Contains("sourcePropertyExpression == "); await Assert.That(result).Contains("targetPropertyExpression == "); - await Assert.That(result).Contains("__BindOneWay_"); + await Assert.That(result).Contains(BindOneWayLocal); } - /// - /// Verifies GenerateCallerFilePathOverload generates file path dispatch. - /// + /// Verifies GenerateCallerFilePathOverload generates file path dispatch. /// A task representing the asynchronous test operation. [Test] public async Task GenerateCallerFilePathOverload_SingleInvocation_GeneratesFilePathDispatch() { var sb = new StringBuilder(); - var inv = ModelFactory.CreateBindingInvocationInfo( - "/src/Views/MyView.cs", - 50); + var inv = ModelFactory.CreateBindingInvocationInfo(); var group = new BindOneWayCodeGenerator.BindingTypeGroup( - "global::TestApp.MyViewModel", - "global::TestApp.MyView", - "global::System.String", - "global::System.String", + MyViewModelTypeName, + MyViewTypeName, + StringTypeName, + StringTypeName, false, false, [inv]); @@ -151,12 +153,10 @@ public async Task GenerateCallerFilePathOverload_SingleInvocation_GeneratesFileP var result = sb.ToString(); await Assert.That(result).Contains("callerLineNumber == 50"); await Assert.That(result).Contains("callerFilePath.EndsWith"); - await Assert.That(result).Contains("__BindOneWay_"); + await Assert.That(result).Contains(BindOneWayLocal); } - /// - /// Verifies GenerateBindOneWayMethod generates PropertyObservable + Subscribe pattern. - /// + /// Verifies GenerateBindOneWayMethod generates PropertyObservable + Subscribe pattern. /// A task representing the asynchronous test operation. [Test] public async Task GenerateBindOneWayMethod_StandardInvocation_GeneratesPropertyObservableSubscribe() @@ -165,7 +165,7 @@ public async Task GenerateBindOneWayMethod_StandardInvocation_GeneratesPropertyO var inv = ModelFactory.CreateBindingInvocationInfo(); var classInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); - BindOneWayCodeGenerator.GenerateBindOneWayMethod(sb, inv, classInfo, "TEST00000000TEST"); + BindOneWayCodeGenerator.GenerateBindOneWayMethod(sb, inv, classInfo, TEST00000000TESTName); var result = sb.ToString(); await Assert.That(result).Contains("__BindOneWay_TEST00000000TEST"); @@ -175,9 +175,7 @@ public async Task GenerateBindOneWayMethod_StandardInvocation_GeneratesPropertyO await Assert.That(result).Contains("target.Text = value"); } - /// - /// Verifies FormatExtraArgs returns empty when no conversion or scheduler. - /// + /// Verifies FormatExtraArgs returns empty when no conversion or scheduler. /// A task representing the asynchronous test operation. [Test] public async Task FormatExtraArgs_NoConversionNoScheduler_ReturnsEmpty() @@ -185,8 +183,8 @@ public async Task FormatExtraArgs_NoConversionNoScheduler_ReturnsEmpty() var group = new BindOneWayCodeGenerator.BindingTypeGroup( "global::TestApp.VM", "global::TestApp.View", - "global::System.String", - "global::System.String", + StringTypeName, + StringTypeName, false, false, []); @@ -196,9 +194,7 @@ public async Task FormatExtraArgs_NoConversionNoScheduler_ReturnsEmpty() await Assert.That(result).IsEqualTo(string.Empty); } - /// - /// Verifies FormatExtraArgs includes conversion function when HasConversion is true. - /// + /// Verifies FormatExtraArgs includes conversion function when HasConversion is true. /// A task representing the asynchronous test operation. [Test] public async Task FormatExtraArgs_WithConversion_IncludesConversionFunc() @@ -206,36 +202,30 @@ public async Task FormatExtraArgs_WithConversion_IncludesConversionFunc() var group = new BindOneWayCodeGenerator.BindingTypeGroup( "global::TestApp.VM", "global::TestApp.View", - "global::System.String", - "global::System.String", + StringTypeName, + StringTypeName, true, false, []); var result = BindOneWayCodeGenerator.FormatExtraArgs(group); - await Assert.That(result).Contains("conversionFunc"); + await Assert.That(result).Contains(ConversionFuncName); } - /// - /// Verifies FormatExtraMethodParams returns empty when no extra params. - /// + /// Verifies FormatExtraMethodParams returns empty when no extra params. /// A task representing the asynchronous test operation. [Test] public async Task FormatExtraMethodParams_NoConversionNoScheduler_ReturnsEmpty() { - var inv = ModelFactory.CreateBindingInvocationInfo( - hasConversion: false, - hasScheduler: false); + var inv = ModelFactory.CreateBindingInvocationInfo(); var result = BindOneWayCodeGenerator.FormatExtraMethodParams(inv); await Assert.That(result).IsEqualTo(string.Empty); } - /// - /// Verifies FormatExtraMethodParams includes Func type when HasConversion is true. - /// + /// Verifies FormatExtraMethodParams includes Func type when HasConversion is true. /// A task representing the asynchronous test operation. [Test] public async Task FormatExtraMethodParams_WithConversion_IncludesFuncParam() @@ -245,12 +235,10 @@ public async Task FormatExtraMethodParams_WithConversion_IncludesFuncParam() var result = BindOneWayCodeGenerator.FormatExtraMethodParams(inv); await Assert.That(result).Contains("global::System.Func<"); - await Assert.That(result).Contains("conversionFunc"); + await Assert.That(result).Contains(ConversionFuncName); } - /// - /// Verifies FormatExtraMethodParams includes IScheduler when HasScheduler is true. - /// + /// Verifies FormatExtraMethodParams includes IScheduler when HasScheduler is true. /// A task representing the asynchronous test operation. [Test] public async Task FormatExtraMethodParams_WithScheduler_IncludesSchedulerParam() @@ -263,9 +251,7 @@ public async Task FormatExtraMethodParams_WithScheduler_IncludesSchedulerParam() await Assert.That(result).Contains("scheduler"); } - /// - /// Verifies GenerateBindOneWayMethod with conversion includes .Select chain. - /// + /// Verifies GenerateBindOneWayMethod with conversion includes .Select chain. /// A task representing the asynchronous test operation. [Test] public async Task GenerateBindOneWayMethod_WithConversion_IncludesSelectChain() @@ -274,16 +260,14 @@ public async Task GenerateBindOneWayMethod_WithConversion_IncludesSelectChain() var inv = ModelFactory.CreateBindingInvocationInfo(hasConversion: true); var classInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); - BindOneWayCodeGenerator.GenerateBindOneWayMethod(sb, inv, classInfo, "TEST00000000TEST"); + BindOneWayCodeGenerator.GenerateBindOneWayMethod(sb, inv, classInfo, TEST00000000TESTName); var result = sb.ToString(); await Assert.That(result).Contains("RxBindingExtensions.Select"); - await Assert.That(result).Contains("conversionFunc"); + await Assert.That(result).Contains(ConversionFuncName); } - /// - /// Verifies GenerateBindOneWayMethod with scheduler includes .ObserveOn chain. - /// + /// Verifies GenerateBindOneWayMethod with scheduler includes .ObserveOn chain. /// A task representing the asynchronous test operation. [Test] public async Task GenerateBindOneWayMethod_WithScheduler_IncludesObserveOn() @@ -292,7 +276,7 @@ public async Task GenerateBindOneWayMethod_WithScheduler_IncludesObserveOn() var inv = ModelFactory.CreateBindingInvocationInfo(hasScheduler: true); var classInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); - BindOneWayCodeGenerator.GenerateBindOneWayMethod(sb, inv, classInfo, "TEST00000000TEST"); + BindOneWayCodeGenerator.GenerateBindOneWayMethod(sb, inv, classInfo, TEST00000000TESTName); var result = sb.ToString(); await Assert.That(result).Contains("ObserveOn"); diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/BindTwoWayCodeGeneratorHelperTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/BindTwoWayCodeGeneratorHelperTests.cs index 4dff33a..2f230cc 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/BindTwoWayCodeGeneratorHelperTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/BindTwoWayCodeGeneratorHelperTests.cs @@ -10,41 +10,70 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests.CodeGeneration; -/// -/// Tests for helper methods. -/// +/// Tests for helper methods. public class BindTwoWayCodeGeneratorHelperTests { - /// - /// Verifies GroupByTypeSignature groups invocations with the same type signature. - /// + /// The BindTwoWay name these tests generate against. + private const string BindTwoWayName = "BindTwoWay"; + + /// The __BindTwoWay_ local the generated code is expected to emit. + private const string BindTwoWayLocal = "__BindTwoWay_"; + + /// The fully qualified name of the String type used by these tests. + private const string StringTypeName = "global::System.String"; + + /// The fully qualified name of the MyView type used by these tests. + private const string MyViewTypeName = "global::TestApp.MyView"; + + /// The fully qualified name of the MyViewModel type used by these tests. + private const string MyViewModelTypeName = "global::TestApp.MyViewModel"; + + /// The fully qualified name of the View type used by these tests. + private const string ViewTypeName = "global::TestApp.View"; + + /// The fully qualified name of the VM type used by these tests. + private const string VMTypeName = "global::TestApp.VM"; + + /// The MyView name these tests generate against. + private const string MyViewName = "MyView"; + + /// The sourceToTargetConv name these tests generate against. + private const string SourceToTargetConvName = "sourceToTargetConv"; + + /// The targetToSourceConv name these tests generate against. + private const string TargetToSourceConvName = "targetToSourceConv"; + + /// The TEST00000000TEST name these tests generate against. + private const string TEST00000000TESTName = "TEST00000000TEST"; + + /// Verifies GroupByTypeSignature groups invocations with the same type signature. /// A task representing the asynchronous test operation. [Test] public async Task GroupByTypeSignature_SameSignature_GroupedTogether() { + const int ExpectedInvocationCount = 2; var inv1 = ModelFactory.CreateBindingInvocationInfo( callerLineNumber: 10, isTwoWay: true, - methodName: "BindTwoWay"); + methodName: BindTwoWayName); var inv2 = ModelFactory.CreateBindingInvocationInfo( callerLineNumber: 20, isTwoWay: true, - methodName: "BindTwoWay"); + methodName: BindTwoWayName); var invocations = ImmutableArray.Create(inv1, inv2); var groups = BindTwoWayCodeGenerator.GroupByTypeSignature(invocations); await Assert.That(groups.Count).IsEqualTo(1); - await Assert.That(groups[0].Invocations.Length).IsEqualTo(2); + await Assert.That(groups[0].Invocations.Length).IsEqualTo(ExpectedInvocationCount); } - /// - /// Verifies GroupByTypeSignature separates invocations with different target types. - /// + /// Verifies GroupByTypeSignature separates invocations with different target types. /// A task representing the asynchronous test operation. [Test] public async Task GroupByTypeSignature_DifferentTargetTypes_SeparateGroups() { + const int ExpectedGroupCount = 2; var inv1 = ModelFactory.CreateBindingInvocationInfo( targetTypeFullName: "global::TestApp.ViewA", isTwoWay: true); @@ -55,23 +84,21 @@ public async Task GroupByTypeSignature_DifferentTargetTypes_SeparateGroups() var groups = BindTwoWayCodeGenerator.GroupByTypeSignature(invocations); - await Assert.That(groups.Count).IsEqualTo(2); + await Assert.That(groups.Count).IsEqualTo(ExpectedGroupCount); } - /// - /// Verifies GenerateConcreteOverload dispatches to CallerArgExpr when supported. - /// + /// Verifies GenerateConcreteOverload dispatches to CallerArgExpr when supported. /// A task representing the asynchronous test operation. [Test] public async Task GenerateConcreteOverload_CallerArgExprSupported_GeneratesCallerArgExprOverload() { var sb = new StringBuilder(); - var inv = ModelFactory.CreateBindingInvocationInfo(isTwoWay: true, methodName: "BindTwoWay"); + var inv = ModelFactory.CreateBindingInvocationInfo(isTwoWay: true, methodName: BindTwoWayName); var group = new BindTwoWayCodeGenerator.BindingTypeGroup( - "global::TestApp.MyViewModel", - "global::TestApp.MyView", - "global::System.String", - "global::System.String", + MyViewModelTypeName, + MyViewTypeName, + StringTypeName, + StringTypeName, false, false, [inv]); @@ -80,23 +107,21 @@ public async Task GenerateConcreteOverload_CallerArgExprSupported_GeneratesCalle var result = sb.ToString(); await Assert.That(result).Contains("CallerArgumentExpression"); - await Assert.That(result).Contains("__BindTwoWay_"); + await Assert.That(result).Contains(BindTwoWayLocal); } - /// - /// Verifies GenerateConcreteOverload dispatches to CallerFilePath when not supported. - /// + /// Verifies GenerateConcreteOverload dispatches to CallerFilePath when not supported. /// A task representing the asynchronous test operation. [Test] public async Task GenerateConcreteOverload_CallerArgExprNotSupported_GeneratesCallerFilePathOverload() { var sb = new StringBuilder(); - var inv = ModelFactory.CreateBindingInvocationInfo(isTwoWay: true, methodName: "BindTwoWay"); + var inv = ModelFactory.CreateBindingInvocationInfo(isTwoWay: true, methodName: BindTwoWayName); var group = new BindTwoWayCodeGenerator.BindingTypeGroup( - "global::TestApp.MyViewModel", - "global::TestApp.MyView", - "global::System.String", - "global::System.String", + MyViewModelTypeName, + MyViewTypeName, + StringTypeName, + StringTypeName, false, false, [inv]); @@ -108,9 +133,7 @@ public async Task GenerateConcreteOverload_CallerArgExprNotSupported_GeneratesCa await Assert.That(result).Contains("callerLineNumber"); } - /// - /// Verifies GenerateCallerArgExprOverload generates dual expression dispatch. - /// + /// Verifies GenerateCallerArgExprOverload generates dual expression dispatch. /// A task representing the asynchronous test operation. [Test] public async Task GenerateCallerArgExprOverload_SingleInvocation_GeneratesDualExpressionDispatch() @@ -118,14 +141,12 @@ public async Task GenerateCallerArgExprOverload_SingleInvocation_GeneratesDualEx var sb = new StringBuilder(); var inv = ModelFactory.CreateBindingInvocationInfo( isTwoWay: true, - methodName: "BindTwoWay", - sourceExpressionText: "x => x.Name", - targetExpressionText: "x => x.Text"); + methodName: BindTwoWayName); var group = new BindTwoWayCodeGenerator.BindingTypeGroup( - "global::TestApp.MyViewModel", - "global::TestApp.MyView", - "global::System.String", - "global::System.String", + MyViewModelTypeName, + MyViewTypeName, + StringTypeName, + StringTypeName, false, false, [inv]); @@ -135,27 +156,26 @@ public async Task GenerateCallerArgExprOverload_SingleInvocation_GeneratesDualEx var result = sb.ToString(); await Assert.That(result).Contains("sourcePropertyExpression == "); await Assert.That(result).Contains("targetPropertyExpression == "); - await Assert.That(result).Contains("__BindTwoWay_"); + await Assert.That(result).Contains(BindTwoWayLocal); } - /// - /// Verifies GenerateCallerFilePathOverload generates file path dispatch. - /// + /// Verifies GenerateCallerFilePathOverload generates file path dispatch. /// A task representing the asynchronous test operation. [Test] public async Task GenerateCallerFilePathOverload_SingleInvocation_GeneratesFilePathDispatch() { + const int CallerLineNumber = 55; var sb = new StringBuilder(); var inv = ModelFactory.CreateBindingInvocationInfo( "/src/Views/MyView.cs", - 55, + CallerLineNumber, isTwoWay: true, - methodName: "BindTwoWay"); + methodName: BindTwoWayName); var group = new BindTwoWayCodeGenerator.BindingTypeGroup( - "global::TestApp.MyViewModel", - "global::TestApp.MyView", - "global::System.String", - "global::System.String", + MyViewModelTypeName, + MyViewTypeName, + StringTypeName, + StringTypeName, false, false, [inv]); @@ -165,25 +185,23 @@ public async Task GenerateCallerFilePathOverload_SingleInvocation_GeneratesFileP var result = sb.ToString(); await Assert.That(result).Contains("callerLineNumber == 55"); await Assert.That(result).Contains("callerFilePath.EndsWith"); - await Assert.That(result).Contains("__BindTwoWay_"); + await Assert.That(result).Contains(BindTwoWayLocal); } - /// - /// Verifies GenerateBindTwoWayMethod generates PropertyObservable + CompositeDisposable pattern. - /// + /// Verifies GenerateBindTwoWayMethod generates PropertyObservable + CompositeDisposable pattern. /// A task representing the asynchronous test operation. [Test] public async Task GenerateBindTwoWayMethod_StandardInvocation_GeneratesCompositeDisposable() { var sb = new StringBuilder(); - var inv = ModelFactory.CreateBindingInvocationInfo(isTwoWay: true, methodName: "BindTwoWay"); + var inv = ModelFactory.CreateBindingInvocationInfo(isTwoWay: true, methodName: BindTwoWayName); var sourceClassInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); var targetClassInfo = ModelFactory.CreateClassBindingInfo( - "global::TestApp.MyView", - "MyView", + MyViewTypeName, + MyViewName, implementsINPC: true); - BindTwoWayCodeGenerator.GenerateBindTwoWayMethod(sb, inv, sourceClassInfo, targetClassInfo, "TEST00000000TEST"); + BindTwoWayCodeGenerator.GenerateBindTwoWayMethod(sb, inv, sourceClassInfo, targetClassInfo, TEST00000000TESTName); var result = sb.ToString(); await Assert.That(result).Contains("__BindTwoWay_TEST00000000TEST"); @@ -194,18 +212,16 @@ public async Task GenerateBindTwoWayMethod_StandardInvocation_GeneratesComposite await Assert.That(result).Contains("source.Name = value"); } - /// - /// Verifies FormatExtraArgs returns empty when no conversion or scheduler. - /// + /// Verifies FormatExtraArgs returns empty when no conversion or scheduler. /// A task representing the asynchronous test operation. [Test] public async Task FormatExtraArgs_NoConversionNoScheduler_ReturnsEmpty() { var group = new BindTwoWayCodeGenerator.BindingTypeGroup( - "global::TestApp.VM", - "global::TestApp.View", - "global::System.String", - "global::System.String", + VMTypeName, + ViewTypeName, + StringTypeName, + StringTypeName, false, false, []); @@ -215,40 +231,36 @@ public async Task FormatExtraArgs_NoConversionNoScheduler_ReturnsEmpty() await Assert.That(result).IsEqualTo(string.Empty); } - /// - /// Verifies FormatExtraArgs includes two-way converter args when HasConversion is true. - /// + /// Verifies FormatExtraArgs includes two-way converter args when HasConversion is true. /// A task representing the asynchronous test operation. [Test] public async Task FormatExtraArgs_WithConversion_IncludesTwoWayConverterArgs() { var group = new BindTwoWayCodeGenerator.BindingTypeGroup( - "global::TestApp.VM", - "global::TestApp.View", - "global::System.String", - "global::System.String", + VMTypeName, + ViewTypeName, + StringTypeName, + StringTypeName, true, false, []); var result = BindTwoWayCodeGenerator.FormatExtraArgs(group); - await Assert.That(result).Contains("sourceToTargetConv"); - await Assert.That(result).Contains("targetToSourceConv"); + await Assert.That(result).Contains(SourceToTargetConvName); + await Assert.That(result).Contains(TargetToSourceConvName); } - /// - /// Verifies FormatExtraArgs includes scheduler when HasScheduler is true. - /// + /// Verifies FormatExtraArgs includes scheduler when HasScheduler is true. /// A task representing the asynchronous test operation. [Test] public async Task FormatExtraArgs_WithScheduler_IncludesSchedulerArg() { var group = new BindTwoWayCodeGenerator.BindingTypeGroup( - "global::TestApp.VM", - "global::TestApp.View", - "global::System.String", - "global::System.String", + VMTypeName, + ViewTypeName, + StringTypeName, + StringTypeName, false, true, []); @@ -258,9 +270,7 @@ public async Task FormatExtraArgs_WithScheduler_IncludesSchedulerArg() await Assert.That(result).Contains("scheduler"); } - /// - /// Verifies FormatExtraMethodParams returns empty when no conversion or scheduler. - /// + /// Verifies FormatExtraMethodParams returns empty when no conversion or scheduler. /// A task representing the asynchronous test operation. [Test] public async Task FormatExtraMethodParams_NoConversionNoScheduler_ReturnsEmpty() @@ -269,16 +279,14 @@ public async Task FormatExtraMethodParams_NoConversionNoScheduler_ReturnsEmpty() hasConversion: false, hasScheduler: false, isTwoWay: true, - methodName: "BindTwoWay"); + methodName: BindTwoWayName); var result = BindTwoWayCodeGenerator.FormatExtraMethodParams(inv); await Assert.That(result).IsEqualTo(string.Empty); } - /// - /// Verifies FormatExtraMethodParams includes two-way Func params when HasConversion is true. - /// + /// Verifies FormatExtraMethodParams includes two-way Func params when HasConversion is true. /// A task representing the asynchronous test operation. [Test] public async Task FormatExtraMethodParams_WithConversion_IncludesTwoWayFuncParams() @@ -286,18 +294,16 @@ public async Task FormatExtraMethodParams_WithConversion_IncludesTwoWayFuncParam var inv = ModelFactory.CreateBindingInvocationInfo( hasConversion: true, isTwoWay: true, - methodName: "BindTwoWay"); + methodName: BindTwoWayName); var result = BindTwoWayCodeGenerator.FormatExtraMethodParams(inv); - await Assert.That(result).Contains("sourceToTargetConv"); - await Assert.That(result).Contains("targetToSourceConv"); + await Assert.That(result).Contains(SourceToTargetConvName); + await Assert.That(result).Contains(TargetToSourceConvName); await Assert.That(result).Contains("global::System.Func<"); } - /// - /// Verifies GenerateBindTwoWayMethod with conversion includes .Select chains. - /// + /// Verifies GenerateBindTwoWayMethod with conversion includes .Select chains. /// A task representing the asynchronous test operation. [Test] public async Task GenerateBindTwoWayMethod_WithConversion_IncludesSelectChains() @@ -306,24 +312,22 @@ public async Task GenerateBindTwoWayMethod_WithConversion_IncludesSelectChains() var inv = ModelFactory.CreateBindingInvocationInfo( hasConversion: true, isTwoWay: true, - methodName: "BindTwoWay"); + methodName: BindTwoWayName); var sourceClassInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); var targetClassInfo = ModelFactory.CreateClassBindingInfo( - "global::TestApp.MyView", - "MyView", + MyViewTypeName, + MyViewName, implementsINPC: true); - BindTwoWayCodeGenerator.GenerateBindTwoWayMethod(sb, inv, sourceClassInfo, targetClassInfo, "TEST00000000TEST"); + BindTwoWayCodeGenerator.GenerateBindTwoWayMethod(sb, inv, sourceClassInfo, targetClassInfo, TEST00000000TESTName); var result = sb.ToString(); await Assert.That(result).Contains("RxBindingExtensions.Select"); - await Assert.That(result).Contains("sourceToTargetConv"); - await Assert.That(result).Contains("targetToSourceConv"); + await Assert.That(result).Contains(SourceToTargetConvName); + await Assert.That(result).Contains(TargetToSourceConvName); } - /// - /// Verifies GenerateBindTwoWayMethod with scheduler includes .ObserveOn chains. - /// + /// Verifies GenerateBindTwoWayMethod with scheduler includes .ObserveOn chains. /// A task representing the asynchronous test operation. [Test] public async Task GenerateBindTwoWayMethod_WithScheduler_IncludesObserveOnChains() @@ -332,54 +336,50 @@ public async Task GenerateBindTwoWayMethod_WithScheduler_IncludesObserveOnChains var inv = ModelFactory.CreateBindingInvocationInfo( hasScheduler: true, isTwoWay: true, - methodName: "BindTwoWay"); + methodName: BindTwoWayName); var sourceClassInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); var targetClassInfo = ModelFactory.CreateClassBindingInfo( - "global::TestApp.MyView", - "MyView", + MyViewTypeName, + MyViewName, implementsINPC: true); - BindTwoWayCodeGenerator.GenerateBindTwoWayMethod(sb, inv, sourceClassInfo, targetClassInfo, "TEST00000000TEST"); + BindTwoWayCodeGenerator.GenerateBindTwoWayMethod(sb, inv, sourceClassInfo, targetClassInfo, TEST00000000TESTName); var result = sb.ToString(); await Assert.That(result).Contains("ObserveOn"); await Assert.That(result).Contains("scheduler"); } - /// - /// Verifies GenerateBindTwoWayMethod generates Skip(1) on target observable. - /// + /// Verifies GenerateBindTwoWayMethod generates Skip(1) on target observable. /// A task representing the asynchronous test operation. [Test] public async Task GenerateBindTwoWayMethod_AlwaysGeneratesSkipOne() { var sb = new StringBuilder(); - var inv = ModelFactory.CreateBindingInvocationInfo(isTwoWay: true, methodName: "BindTwoWay"); + var inv = ModelFactory.CreateBindingInvocationInfo(isTwoWay: true, methodName: BindTwoWayName); var sourceClassInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); var targetClassInfo = ModelFactory.CreateClassBindingInfo( - "global::TestApp.MyView", - "MyView", + MyViewTypeName, + MyViewName, implementsINPC: true); - BindTwoWayCodeGenerator.GenerateBindTwoWayMethod(sb, inv, sourceClassInfo, targetClassInfo, "TEST00000000TEST"); + BindTwoWayCodeGenerator.GenerateBindTwoWayMethod(sb, inv, sourceClassInfo, targetClassInfo, TEST00000000TESTName); var result = sb.ToString(); await Assert.That(result).Contains("Skip"); } - /// - /// Verifies AppendExtraParameters appends conversion parameters with correct types. - /// + /// Verifies AppendExtraParameters appends conversion parameters with correct types. /// A task representing the asynchronous test operation. [Test] public async Task AppendExtraParameters_WithConversion_AppendsConverterParamsWithTypes() { var sb = new StringBuilder(); var group = new BindTwoWayCodeGenerator.BindingTypeGroup( - "global::TestApp.VM", - "global::TestApp.View", + VMTypeName, + ViewTypeName, "global::System.Int32", - "global::System.String", + StringTypeName, true, false, []); diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/CodeGeneratorHelpersTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/CodeGeneratorHelpersTests.cs index 7d9940b..20b230f 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/CodeGeneratorHelpersTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/CodeGeneratorHelpersTests.cs @@ -10,35 +10,41 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests.CodeGeneration; -/// -/// Tests for methods. -/// +/// Tests for methods. public class CodeGeneratorHelpersTests { - /// - /// Verifies BuildPropertyAccessChain with a single segment produces "root.Property". - /// + /// The Address name these tests generate against. + private const string AddressName = "Address"; + + /// The fully qualified name of the MyViewModel type used by these tests. + private const string MyViewModelTypeName = "global::TestApp.MyViewModel"; + + /// The /src/Test.cs name these tests generate against. + private const string SrcTestcsName = "/src/Test.cs"; + + /// The x => x.Name property selector these tests bind against. + private const string NameSelector = "x => x.Name"; + + /// Verifies BuildPropertyAccessChain with a single segment produces "root.Property". /// A task representing the asynchronous test operation. [Test] public async Task BuildPropertyAccessChain_SingleSegment_ReturnsDottedPath() { var path = new EquatableArray( - [ModelFactory.CreatePropertyPathSegment("Name")]); + [ModelFactory.CreatePropertyPathSegment()]); var result = CodeGeneratorHelpers.BuildPropertyAccessChain("obj", path); await Assert.That(result).IsEqualTo("obj.Name"); } - /// - /// Verifies BuildPropertyAccessChain with multiple segments produces "root.A.B". - /// + /// Verifies BuildPropertyAccessChain with multiple segments produces "root.A.B". /// A task representing the asynchronous test operation. [Test] public async Task BuildPropertyAccessChain_MultiSegment_ReturnsDottedPath() { var path = new EquatableArray([ - ModelFactory.CreatePropertyPathSegment("Address", "global::TestApp.Address"), + ModelFactory.CreatePropertyPathSegment(AddressName, "global::TestApp.Address"), ModelFactory.CreatePropertyPathSegment("City", "global::System.String", "global::TestApp.Address") ]); @@ -47,9 +53,7 @@ public async Task BuildPropertyAccessChain_MultiSegment_ReturnsDottedPath() await Assert.That(result).IsEqualTo("obj.Address.City"); } - /// - /// Verifies BuildPropertyAccessChain with an empty path returns just the root. - /// + /// Verifies BuildPropertyAccessChain with an empty path returns just the root. /// A task representing the asynchronous test operation. [Test] public async Task BuildPropertyAccessChain_EmptyPath_ReturnsRoot() @@ -61,30 +65,26 @@ public async Task BuildPropertyAccessChain_EmptyPath_ReturnsRoot() await Assert.That(result).IsEqualTo("obj"); } - /// - /// Verifies BuildPropertyPathString produces dotted property names for a single segment. - /// + /// Verifies BuildPropertyPathString produces dotted property names for a single segment. /// A task representing the asynchronous test operation. [Test] public async Task BuildPropertyPathString_SingleSegment_ReturnsPropertyName() { var path = new EquatableArray( - [ModelFactory.CreatePropertyPathSegment("Name")]); + [ModelFactory.CreatePropertyPathSegment()]); var result = CodeGeneratorHelpers.BuildPropertyPathString(path); await Assert.That(result).IsEqualTo("Name"); } - /// - /// Verifies BuildPropertyPathString produces dotted names for multiple segments. - /// + /// Verifies BuildPropertyPathString produces dotted names for multiple segments. /// A task representing the asynchronous test operation. [Test] public async Task BuildPropertyPathString_MultiSegment_ReturnsDottedPath() { var path = new EquatableArray([ - ModelFactory.CreatePropertyPathSegment("Address"), + ModelFactory.CreatePropertyPathSegment(AddressName), ModelFactory.CreatePropertyPathSegment("City") ]); @@ -93,9 +93,7 @@ public async Task BuildPropertyPathString_MultiSegment_ReturnsDottedPath() await Assert.That(result).IsEqualTo("Address.City"); } - /// - /// Verifies BuildPropertyPathString returns empty string for empty path. - /// + /// Verifies BuildPropertyPathString returns empty string for empty path. /// A task representing the asynchronous test operation. [Test] public async Task BuildPropertyPathString_EmptyPath_ReturnsEmptyString() @@ -107,9 +105,7 @@ public async Task BuildPropertyPathString_EmptyPath_ReturnsEmptyString() await Assert.That(result).IsEqualTo(string.Empty); } - /// - /// Verifies ComputePathSuffix returns the last two path segments. - /// + /// Verifies ComputePathSuffix returns the last two path segments. /// A task representing the asynchronous test operation. [Test] public async Task ComputePathSuffix_NormalPath_ReturnsLastTwoSegments() @@ -119,9 +115,7 @@ public async Task ComputePathSuffix_NormalPath_ReturnsLastTwoSegments() await Assert.That(result).IsEqualTo("ViewModels/MyViewModel.cs"); } - /// - /// Verifies ComputePathSuffix returns just the filename for a single-segment path. - /// + /// Verifies ComputePathSuffix returns just the filename for a single-segment path. /// A task representing the asynchronous test operation. [Test] public async Task ComputePathSuffix_SingleSegment_ReturnsFilename() @@ -131,9 +125,7 @@ public async Task ComputePathSuffix_SingleSegment_ReturnsFilename() await Assert.That(result).IsEqualTo("MyViewModel.cs"); } - /// - /// Verifies ComputePathSuffix returns empty for empty input. - /// + /// Verifies ComputePathSuffix returns empty for empty input. /// A task representing the asynchronous test operation. [Test] public async Task ComputePathSuffix_EmptyString_ReturnsEmpty() @@ -143,9 +135,7 @@ public async Task ComputePathSuffix_EmptyString_ReturnsEmpty() await Assert.That(result).IsEqualTo(string.Empty); } - /// - /// Verifies ComputePathSuffix normalizes backslashes to forward slashes. - /// + /// Verifies ComputePathSuffix normalizes backslashes to forward slashes. /// A task representing the asynchronous test operation. [Test] public async Task ComputePathSuffix_Backslashes_NormalizesToForwardSlashes() @@ -155,9 +145,7 @@ public async Task ComputePathSuffix_Backslashes_NormalizesToForwardSlashes() await Assert.That(result).IsEqualTo("ViewModels/MyViewModel.cs"); } - /// - /// Verifies EscapeString escapes double quotes. - /// + /// Verifies EscapeString escapes double quotes. /// A task representing the asynchronous test operation. [Test] public async Task EscapeString_WithQuotes_EscapesQuotes() @@ -167,9 +155,7 @@ public async Task EscapeString_WithQuotes_EscapesQuotes() await Assert.That(result).IsEqualTo("say \\\"hello\\\""); } - /// - /// Verifies EscapeString escapes backslashes. - /// + /// Verifies EscapeString escapes backslashes. /// A task representing the asynchronous test operation. [Test] public async Task EscapeString_WithBackslashes_EscapesBackslashes() @@ -179,37 +165,31 @@ public async Task EscapeString_WithBackslashes_EscapesBackslashes() await Assert.That(result).IsEqualTo("path\\\\to\\\\file"); } - /// - /// Verifies EscapeString leaves clean strings unchanged. - /// + /// Verifies EscapeString leaves clean strings unchanged. /// A task representing the asynchronous test operation. [Test] public async Task EscapeString_CleanString_ReturnsUnchanged() { - var result = CodeGeneratorHelpers.EscapeString("x => x.Name"); + var result = CodeGeneratorHelpers.EscapeString(NameSelector); - await Assert.That(result).IsEqualTo("x => x.Name"); + await Assert.That(result).IsEqualTo(NameSelector); } - /// - /// Verifies FindClassInfo returns matching class info when found. - /// + /// Verifies FindClassInfo returns matching class info when found. /// A task representing the asynchronous test operation. [Test] public async Task FindClassInfo_Found_ReturnsMatchingInfo() { - var classInfo = ModelFactory.CreateClassBindingInfo("global::TestApp.MyViewModel"); + var classInfo = ModelFactory.CreateClassBindingInfo(); var allClasses = ImmutableArray.Create(classInfo); - var result = CodeGeneratorHelpers.FindClassInfo(allClasses, "global::TestApp.MyViewModel"); + var result = CodeGeneratorHelpers.FindClassInfo(allClasses, MyViewModelTypeName); await Assert.That(result).IsNotNull(); - await Assert.That(result!.FullyQualifiedName).IsEqualTo("global::TestApp.MyViewModel"); + await Assert.That(result!.FullyQualifiedName).IsEqualTo(MyViewModelTypeName); } - /// - /// Verifies FindClassInfo returns null when class info is not found. - /// + /// Verifies FindClassInfo returns null when class info is not found. /// A task representing the asynchronous test operation. [Test] public async Task FindClassInfo_NotFound_ReturnsNull() @@ -217,35 +197,31 @@ public async Task FindClassInfo_NotFound_ReturnsNull() var classInfo = ModelFactory.CreateClassBindingInfo("global::TestApp.OtherType"); var allClasses = ImmutableArray.Create(classInfo); - var result = CodeGeneratorHelpers.FindClassInfo(allClasses, "global::TestApp.MyViewModel"); + var result = CodeGeneratorHelpers.FindClassInfo(allClasses, MyViewModelTypeName); await Assert.That(result).IsNull(); } - /// - /// Verifies FindClassInfo returns null for empty array. - /// + /// Verifies FindClassInfo returns null for empty array. /// A task representing the asynchronous test operation. [Test] public async Task FindClassInfo_EmptyArray_ReturnsNull() { var allClasses = ImmutableArray.Empty; - var result = CodeGeneratorHelpers.FindClassInfo(allClasses, "global::TestApp.MyViewModel"); + var result = CodeGeneratorHelpers.FindClassInfo(allClasses, MyViewModelTypeName); await Assert.That(result).IsNull(); } - /// - /// Verifies AppendExtensionClassHeader produces expected structure. - /// + /// Verifies AppendExtensionClassHeader produces expected structure. /// A task representing the asynchronous test operation. [Test] public async Task AppendExtensionClassHeader_ProducesExpectedStructure() { var sb = new StringBuilder(); - CodeGeneratorHelpers.AppendExtensionClassHeader(sb, new LanguageFeatures(false, true, true)); + CodeGeneratorHelpers.AppendExtensionClassHeader(sb, new(false, true, true)); var result = sb.ToString(); await Assert.That(result).Contains("// "); @@ -254,9 +230,7 @@ public async Task AppendExtensionClassHeader_ProducesExpectedStructure() await Assert.That(result).Contains("__ReactiveUIGeneratedBindings"); } - /// - /// Verifies AppendExtensionClassFooter produces closing braces. - /// + /// Verifies AppendExtensionClassFooter produces closing braces. /// A task representing the asynchronous test operation. [Test] public async Task AppendExtensionClassFooter_ProducesClosingBraces() @@ -269,15 +243,13 @@ public async Task AppendExtensionClassFooter_ProducesClosingBraces() await Assert.That(result).Contains("}"); } - /// - /// Verifies BuildPropertyAccessLambda delegates to BuildPropertyAccessChain. - /// + /// Verifies BuildPropertyAccessLambda delegates to BuildPropertyAccessChain. /// A task representing the asynchronous test operation. [Test] public async Task BuildPropertyAccessLambda_ReturnsParameterDotPath() { var path = new EquatableArray([ - ModelFactory.CreatePropertyPathSegment("Address"), + ModelFactory.CreatePropertyPathSegment(AddressName), ModelFactory.CreatePropertyPathSegment("City") ]); @@ -286,9 +258,7 @@ public async Task BuildPropertyAccessLambda_ReturnsParameterDotPath() await Assert.That(result).IsEqualTo("x.Address.City"); } - /// - /// Verifies BuildPropertySetterChain delegates to BuildPropertyAccessChain. - /// + /// Verifies BuildPropertySetterChain delegates to BuildPropertyAccessChain. /// A task representing the asynchronous test operation. [Test] public async Task BuildPropertySetterChain_ReturnsRootDotPath() @@ -301,22 +271,18 @@ public async Task BuildPropertySetterChain_ReturnsRootDotPath() await Assert.That(result).IsEqualTo("target.Text"); } - /// - /// Verifies StableStringHash is deterministic across multiple calls. - /// + /// Verifies StableStringHash is deterministic across multiple calls. /// A task representing the asynchronous test operation. [Test] public async Task StableStringHash_SameInput_ReturnsSameHash() { - var hash1 = CodeGeneratorHelpers.StableStringHash("global::TestApp.MyViewModel"); - var hash2 = CodeGeneratorHelpers.StableStringHash("global::TestApp.MyViewModel"); + var hash1 = CodeGeneratorHelpers.StableStringHash(MyViewModelTypeName); + var hash2 = CodeGeneratorHelpers.StableStringHash(MyViewModelTypeName); await Assert.That(hash1).IsEqualTo(hash2); } - /// - /// Verifies StableStringHash returns different hashes for different strings. - /// + /// Verifies StableStringHash returns different hashes for different strings. /// A task representing the asynchronous test operation. [Test] public async Task StableStringHash_DifferentInput_ReturnsDifferentHash() @@ -327,9 +293,7 @@ public async Task StableStringHash_DifferentInput_ReturnsDifferentHash() await Assert.That(hash1).IsNotEqualTo(hash2); } - /// - /// Verifies StableStringHash returns 0 for null input. - /// + /// Verifies StableStringHash returns 0 for null input. /// A task representing the asynchronous test operation. [Test] public async Task StableStringHash_NullInput_ReturnsZero() @@ -339,80 +303,78 @@ public async Task StableStringHash_NullInput_ReturnsZero() await Assert.That(result).IsEqualTo(0); } - /// - /// Verifies ComputeStableMethodSuffix produces a 16-character hex string. - /// + /// Verifies ComputeStableMethodSuffix produces a 16-character hex string. /// A task representing the asynchronous test operation. [Test] public async Task ComputeStableMethodSuffix_ReturnsHexString() { + const int CallerLineNumber = 42; + const int ExpectedResultCount = 16; var result = CodeGeneratorHelpers.ComputeStableMethodSuffix( - "global::TestApp.MyViewModel", - "/src/Test.cs", - 42, - "x => x.Name"); + MyViewModelTypeName, + SrcTestcsName, + CallerLineNumber, + NameSelector); - await Assert.That(result.Length).IsEqualTo(16); + await Assert.That(result.Length).IsEqualTo(ExpectedResultCount); await Assert.That(result.All("0123456789ABCDEF".Contains)).IsTrue(); } - /// - /// Verifies ComputeStableMethodSuffix is deterministic. - /// + /// Verifies ComputeStableMethodSuffix is deterministic. /// A task representing the asynchronous test operation. [Test] public async Task ComputeStableMethodSuffix_SameInput_ReturnsSameResult() { + const int CallerLineNumber = 42; var result1 = CodeGeneratorHelpers.ComputeStableMethodSuffix( - "global::TestApp.MyViewModel", - "/src/Test.cs", - 42, - "x => x.Name"); + MyViewModelTypeName, + SrcTestcsName, + CallerLineNumber, + NameSelector); var result2 = CodeGeneratorHelpers.ComputeStableMethodSuffix( - "global::TestApp.MyViewModel", - "/src/Test.cs", - 42, - "x => x.Name"); + MyViewModelTypeName, + SrcTestcsName, + CallerLineNumber, + NameSelector); await Assert.That(result1).IsEqualTo(result2); } - /// - /// Verifies ComputeStableMethodSuffix produces different results for different discriminators. - /// + /// Verifies ComputeStableMethodSuffix produces different results for different discriminators. /// A task representing the asynchronous test operation. [Test] public async Task ComputeStableMethodSuffix_DifferentDiscriminator_ReturnsDifferentResult() { + const int CallerLineNumber = 42; var result1 = CodeGeneratorHelpers.ComputeStableMethodSuffix( - "global::TestApp.MyViewModel", - "/src/Test.cs", - 42, - "x => x.Name"); + MyViewModelTypeName, + SrcTestcsName, + CallerLineNumber, + NameSelector); var result2 = CodeGeneratorHelpers.ComputeStableMethodSuffix( - "global::TestApp.MyViewModel", - "/src/Test.cs", - 42, + MyViewModelTypeName, + SrcTestcsName, + CallerLineNumber, "x => x.Age"); await Assert.That(result1).IsNotEqualTo(result2); } - /// - /// Verifies ComputeStableMethodSuffix produces different results for different line numbers. - /// + /// Verifies ComputeStableMethodSuffix produces different results for different line numbers. /// A task representing the asynchronous test operation. [Test] public async Task ComputeStableMethodSuffix_DifferentLineNumber_ReturnsDifferentResult() { + const int CallerLineNumber = 10; + const int CallerLineNumber2 = 20; var result1 = CodeGeneratorHelpers.ComputeStableMethodSuffix( - "global::TestApp.MyViewModel", - "/src/Test.cs", - 10); + MyViewModelTypeName, + SrcTestcsName, + CallerLineNumber); var result2 = CodeGeneratorHelpers.ComputeStableMethodSuffix( - "global::TestApp.MyViewModel", - "/src/Test.cs", - 20); + MyViewModelTypeName, + SrcTestcsName, + CallerLineNumber2); await Assert.That(result1).IsNotEqualTo(result2); } @@ -430,28 +392,24 @@ public async Task ComputePathSuffix_OneSlash_ReturnsFullPath() await Assert.That(result).IsEqualTo("folder/MyFile.cs"); } - /// - /// Verifies NormalizeLambdaText strips the "static " prefix from lambda text. - /// + /// Verifies NormalizeLambdaText strips the "static " prefix from lambda text. /// A task representing the asynchronous test operation. [Test] public async Task NormalizeLambdaText_StaticPrefix_StripsPrefix() { var result = CodeGeneratorHelpers.NormalizeLambdaText("static x => x.Name"); - await Assert.That(result).IsEqualTo("x => x.Name"); + await Assert.That(result).IsEqualTo(NameSelector); } - /// - /// Verifies NormalizeLambdaText returns the input unchanged when no "static " prefix is present. - /// + /// Verifies NormalizeLambdaText returns the input unchanged when no "static " prefix is present. /// A task representing the asynchronous test operation. [Test] public async Task NormalizeLambdaText_NoPrefix_ReturnsUnchanged() { - var result = CodeGeneratorHelpers.NormalizeLambdaText("x => x.Name"); + var result = CodeGeneratorHelpers.NormalizeLambdaText(NameSelector); - await Assert.That(result).IsEqualTo("x => x.Name"); + await Assert.That(result).IsEqualTo(NameSelector); } /// @@ -467,9 +425,7 @@ public async Task NormalizeLambdaText_ShortString_ReturnsUnchanged() await Assert.That(result).IsEqualTo("stat"); } - /// - /// Verifies EscapeString handles strings with both quotes and backslashes. - /// + /// Verifies EscapeString handles strings with both quotes and backslashes. /// A task representing the asynchronous test operation. [Test] public async Task EscapeString_MixedSpecialChars_EscapesAll() @@ -479,27 +435,24 @@ public async Task EscapeString_MixedSpecialChars_EscapesAll() await Assert.That(result).IsEqualTo("a\\\\\\\"b"); } - /// - /// Verifies ConditionKeyword returns "if" for index 0. - /// + /// Verifies ConditionKeyword returns "if" for index 0. /// A task representing the asynchronous test operation. [Test] public async Task ConditionKeyword_IndexZero_ReturnsIf() => await Assert.That(CodeGeneratorHelpers.ConditionKeyword(0)).IsEqualTo("if"); - /// - /// Verifies ConditionKeyword returns "else if" for index 1. - /// + /// Verifies ConditionKeyword returns "else if" for index 1. /// A task representing the asynchronous test operation. [Test] public async Task ConditionKeyword_IndexOne_ReturnsElseIf() => await Assert.That(CodeGeneratorHelpers.ConditionKeyword(1)).IsEqualTo("else if"); - /// - /// Verifies ConditionKeyword returns "else if" for index greater than 1. - /// + /// Verifies ConditionKeyword returns "else if" for index greater than 1. /// A task representing the asynchronous test operation. [Test] - public async Task ConditionKeyword_IndexGreaterThanOne_ReturnsElseIf() => - await Assert.That(CodeGeneratorHelpers.ConditionKeyword(5)).IsEqualTo("else if"); + public async Task ConditionKeyword_IndexGreaterThanOne_ReturnsElseIf() + { + const int LaterBranchIndex = 5; + await Assert.That(CodeGeneratorHelpers.ConditionKeyword(LaterBranchIndex)).IsEqualTo("else if"); + } } diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/ObservationCodeGeneratorHelperTests.DeepChain.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/ObservationCodeGeneratorHelperTests.DeepChain.cs index 7d74338..ee28a1e 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/ObservationCodeGeneratorHelperTests.DeepChain.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/ObservationCodeGeneratorHelperTests.DeepChain.cs @@ -9,14 +9,10 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests.CodeGeneration; -/// -/// Tests for — deep-chain and inline observation. -/// +/// Tests for — deep-chain and inline observation. public partial class ObservationCodeGeneratorHelperTests { - /// - /// Verifies GenerateDeepChainObservation generates Select/Switch pattern for two-level chain. - /// + /// Verifies GenerateDeepChainObservation generates Select/Switch pattern for two-level chain. /// A task representing the asynchronous test operation. [Test] public async Task GenerateDeepChainObservation_TwoLevelChain_GeneratesSelectSwitch() @@ -24,13 +20,13 @@ public async Task GenerateDeepChainObservation_TwoLevelChain_GeneratesSelectSwit var sb = new StringBuilder(); var paths = new EquatableArray>([ new([ - ModelFactory.CreatePropertyPathSegment("Address", "global::TestApp.Address"), - ModelFactory.CreatePropertyPathSegment("City", "global::System.String", "global::TestApp.Address") + ModelFactory.CreatePropertyPathSegment(AddressName, AddressTypeName), + ModelFactory.CreatePropertyPathSegment("City", StringTypeName, AddressTypeName) ]) ]); var inv = ModelFactory.CreateInvocationInfo( propertyPaths: paths, - expressionTexts: new EquatableArray(["x => x.Address.City"])); + expressionTexts: new EquatableArray([CitySelector])); var classInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); ObservationCodeGenerator.GenerateDeepChainObservation(sb, inv, classInfo, false); @@ -39,13 +35,11 @@ public async Task GenerateDeepChainObservation_TwoLevelChain_GeneratesSelectSwit await Assert.That(result).Contains("__obs0"); await Assert.That(result).Contains("__obs1"); await Assert.That(result).Contains("RxBindingExtensions.Select("); - await Assert.That(result).Contains("RxBindingExtensions.Switch("); - await Assert.That(result).Contains("RxBindingExtensions.DistinctUntilChanged("); + await Assert.That(result).Contains(RxBindingExtensionsSwitchFragment); + await Assert.That(result).Contains(RxBindingExtensionsDistinctUntilChangedFragment); } - /// - /// Verifies GenerateDeepChainObservation for before-change does not add DistinctUntilChanged. - /// + /// Verifies GenerateDeepChainObservation for before-change does not add DistinctUntilChanged. /// A task representing the asynchronous test operation. [Test] public async Task GenerateDeepChainObservation_BeforeChange_NoDistinctUntilChanged() @@ -53,45 +47,43 @@ public async Task GenerateDeepChainObservation_BeforeChange_NoDistinctUntilChang var sb = new StringBuilder(); var paths = new EquatableArray>([ new([ - ModelFactory.CreatePropertyPathSegment("Address", "global::TestApp.Address"), - ModelFactory.CreatePropertyPathSegment("City", "global::System.String", "global::TestApp.Address") + ModelFactory.CreatePropertyPathSegment(AddressName, AddressTypeName), + ModelFactory.CreatePropertyPathSegment("City", StringTypeName, AddressTypeName) ]) ]); var inv = ModelFactory.CreateInvocationInfo( propertyPaths: paths, isBeforeChange: true, - expressionTexts: new EquatableArray(["x => x.Address.City"])); + expressionTexts: new EquatableArray([CitySelector])); var classInfo = ModelFactory.CreateClassBindingInfo(implementsINPChanging: true); ObservationCodeGenerator.GenerateDeepChainObservation(sb, inv, classInfo, true); var result = sb.ToString(); await Assert.That(result).Contains("PropertyChanging"); - await Assert.That(result).DoesNotContain("DistinctUntilChanged"); + await Assert.That(result).DoesNotContain(DistinctUntilChangedName); } - /// - /// Verifies GenerateDeepChainVariable generates variable declarations for deep chain. - /// + /// Verifies GenerateDeepChainVariable generates variable declarations for deep chain. /// A task representing the asynchronous test operation. [Test] public async Task GenerateDeepChainVariable_TwoLevelChain_GeneratesVariableDeclarations() { var sb = new StringBuilder(); var path = new EquatableArray([ - ModelFactory.CreatePropertyPathSegment("Address", "global::TestApp.Address"), - ModelFactory.CreatePropertyPathSegment("City", "global::System.String", "global::TestApp.Address") + ModelFactory.CreatePropertyPathSegment(AddressName, AddressTypeName), + ModelFactory.CreatePropertyPathSegment("City", StringTypeName, AddressTypeName) ]); var classInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); - ObservationCodeGenerator.GenerateDeepChainVariable(sb, path, classInfo, false, "__propObs0"); + ObservationCodeGenerator.GenerateDeepChainVariable(sb, path, classInfo, false, PropObs0Local); var result = sb.ToString(); await Assert.That(result).Contains("var __propObs0_s0"); await Assert.That(result).Contains("var __propObs0_s1"); await Assert.That(result).Contains("var __propObs0"); - await Assert.That(result).Contains("RxBindingExtensions.Switch("); - await Assert.That(result).Contains("RxBindingExtensions.DistinctUntilChanged("); + await Assert.That(result).Contains(RxBindingExtensionsSwitchFragment); + await Assert.That(result).Contains(RxBindingExtensionsDistinctUntilChangedFragment); } /// @@ -103,140 +95,128 @@ public async Task GenerateDeepChainVariable_BeforeChange_GeneratesPropertyChangi { var sb = new StringBuilder(); var path = new EquatableArray([ - ModelFactory.CreatePropertyPathSegment("Address", "global::TestApp.Address"), - ModelFactory.CreatePropertyPathSegment("City", "global::System.String", "global::TestApp.Address") + ModelFactory.CreatePropertyPathSegment(AddressName, AddressTypeName), + ModelFactory.CreatePropertyPathSegment("City", StringTypeName, AddressTypeName) ]); var classInfo = ModelFactory.CreateClassBindingInfo(implementsINPChanging: true); - ObservationCodeGenerator.GenerateDeepChainVariable(sb, path, classInfo, true, "__propObs0"); + ObservationCodeGenerator.GenerateDeepChainVariable(sb, path, classInfo, true, PropObs0Local); var result = sb.ToString(); await Assert.That(result).Contains("PropertyChanging"); - await Assert.That(result).DoesNotContain("DistinctUntilChanged"); + await Assert.That(result).DoesNotContain(DistinctUntilChangedName); } - /// - /// Verifies EmitInlineObservation with single property INPC generates PropertyObservable. - /// + /// Verifies EmitInlineObservation with single property INPC generates PropertyObservable. /// A task representing the asynchronous test operation. [Test] public async Task EmitInlineObservation_SingleProperty_INPC_GeneratesPropertyObservable() { var sb = new StringBuilder(); var path = new EquatableArray( - [ModelFactory.CreatePropertyPathSegment("Name")]); + [ModelFactory.CreatePropertyPathSegment()]); var classInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); ObservationCodeGenerator.EmitInlineObservation( sb, - "source", + SourceName, path, - "global::System.String", + StringTypeName, classInfo, - "sourceObs"); + SourceObsName); var result = sb.ToString(); - await Assert.That(result).Contains("var sourceObs"); - await Assert.That(result).Contains("PropertyObservable"); + await Assert.That(result).Contains(SourceObsDeclaration); + await Assert.That(result).Contains(PropertyObservableName); } - /// - /// Verifies EmitInlineObservation with single property and no INPC generates ReturnObservable. - /// + /// Verifies EmitInlineObservation with single property and no INPC generates ReturnObservable. /// A task representing the asynchronous test operation. [Test] public async Task EmitInlineObservation_SingleProperty_NoINPC_GeneratesReturnObservable() { var sb = new StringBuilder(); var path = new EquatableArray( - [ModelFactory.CreatePropertyPathSegment("Name")]); + [ModelFactory.CreatePropertyPathSegment()]); var classInfo = ModelFactory.CreateClassBindingInfo(); ObservationCodeGenerator.EmitInlineObservation( sb, - "source", + SourceName, path, - "global::System.String", + StringTypeName, classInfo, - "sourceObs"); + SourceObsName); var result = sb.ToString(); - await Assert.That(result).Contains("var sourceObs"); - await Assert.That(result).Contains("ReturnObservable"); + await Assert.That(result).Contains(SourceObsDeclaration); + await Assert.That(result).Contains(ReturnObservableName); } - /// - /// Verifies EmitInlineObservation with deep chain generates Select/Switch pattern. - /// + /// Verifies EmitInlineObservation with deep chain generates Select/Switch pattern. /// A task representing the asynchronous test operation. [Test] public async Task EmitInlineObservation_DeepChain_GeneratesSelectSwitchPattern() { var sb = new StringBuilder(); var path = new EquatableArray([ - ModelFactory.CreatePropertyPathSegment("Address", "global::TestApp.Address"), - ModelFactory.CreatePropertyPathSegment("City", "global::System.String", "global::TestApp.Address") + ModelFactory.CreatePropertyPathSegment(AddressName, AddressTypeName), + ModelFactory.CreatePropertyPathSegment("City", StringTypeName, AddressTypeName) ]); var classInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); ObservationCodeGenerator.EmitInlineObservation( sb, - "source", + SourceName, path, - "global::System.String", + StringTypeName, classInfo, - "sourceObs"); + SourceObsName); var result = sb.ToString(); - await Assert.That(result).Contains("RxBindingExtensions.Switch("); - await Assert.That(result).Contains("RxBindingExtensions.DistinctUntilChanged("); - await Assert.That(result).Contains("var sourceObs"); + await Assert.That(result).Contains(RxBindingExtensionsSwitchFragment); + await Assert.That(result).Contains(RxBindingExtensionsDistinctUntilChangedFragment); + await Assert.That(result).Contains(SourceObsDeclaration); } - /// - /// Verifies GenerateDeepChainVariable with null classInfo generates after-change code with ReturnObservable fallback. - /// + /// Verifies GenerateDeepChainVariable with null classInfo generates after-change code with ReturnObservable fallback. /// A task representing the asynchronous test operation. [Test] public async Task GenerateDeepChainVariable_NullClassInfo_GeneratesAfterChangeCode() { var sb = new StringBuilder(); var path = new EquatableArray([ - ModelFactory.CreatePropertyPathSegment("Address", "global::TestApp.Address"), - ModelFactory.CreatePropertyPathSegment("City", "global::System.String", "global::TestApp.Address") + ModelFactory.CreatePropertyPathSegment(AddressName, AddressTypeName), + ModelFactory.CreatePropertyPathSegment("City", StringTypeName, AddressTypeName) ]); - ObservationCodeGenerator.GenerateDeepChainVariable(sb, path, null, false, "__propObs0"); + ObservationCodeGenerator.GenerateDeepChainVariable(sb, path, null, false, PropObs0Local); var result = sb.ToString(); await Assert.That(result).Contains("var __propObs0_s0"); - await Assert.That(result).Contains("ReturnObservable"); + await Assert.That(result).Contains(ReturnObservableName); } - /// - /// Verifies GenerateDeepChainVariable with IReactiveObject after-change. - /// + /// Verifies GenerateDeepChainVariable with IReactiveObject after-change. /// A task representing the asynchronous test operation. [Test] public async Task GenerateDeepChainVariable_ReactiveObjectAfterChange_GeneratesPropertyObservable() { var sb = new StringBuilder(); var path = new EquatableArray([ - ModelFactory.CreatePropertyPathSegment("Address", "global::TestApp.Address"), - ModelFactory.CreatePropertyPathSegment("City", "global::System.String", "global::TestApp.Address") + ModelFactory.CreatePropertyPathSegment(AddressName, AddressTypeName), + ModelFactory.CreatePropertyPathSegment("City", StringTypeName, AddressTypeName) ]); var classInfo = ModelFactory.CreateClassBindingInfo(implementsIReactiveObject: true); - ObservationCodeGenerator.GenerateDeepChainVariable(sb, path, classInfo, false, "__propObs0"); + ObservationCodeGenerator.GenerateDeepChainVariable(sb, path, classInfo, false, PropObs0Local); var result = sb.ToString(); - await Assert.That(result).Contains("PropertyObservable"); - await Assert.That(result).Contains("DistinctUntilChanged"); + await Assert.That(result).Contains(PropertyObservableName); + await Assert.That(result).Contains(DistinctUntilChangedName); } - /// - /// Verifies GenerateDeepChainObservation with null classInfo generates after-change code with ReturnObservable fallback. - /// + /// Verifies GenerateDeepChainObservation with null classInfo generates after-change code with ReturnObservable fallback. /// A task representing the asynchronous test operation. [Test] public async Task GenerateDeepChainObservation_NullClassInfo_GeneratesCode() @@ -244,24 +224,22 @@ public async Task GenerateDeepChainObservation_NullClassInfo_GeneratesCode() var sb = new StringBuilder(); var paths = new EquatableArray>([ new([ - ModelFactory.CreatePropertyPathSegment("Address", "global::TestApp.Address"), - ModelFactory.CreatePropertyPathSegment("City", "global::System.String", "global::TestApp.Address") + ModelFactory.CreatePropertyPathSegment(AddressName, AddressTypeName), + ModelFactory.CreatePropertyPathSegment("City", StringTypeName, AddressTypeName) ]) ]); var inv = ModelFactory.CreateInvocationInfo( propertyPaths: paths, - expressionTexts: new EquatableArray(["x => x.Address.City"])); + expressionTexts: new EquatableArray([CitySelector])); ObservationCodeGenerator.GenerateDeepChainObservation(sb, inv, null, false); var result = sb.ToString(); - await Assert.That(result).Contains("ReturnObservable"); + await Assert.That(result).Contains(ReturnObservableName); await Assert.That(result).Contains("Switch"); } - /// - /// Verifies GenerateDeepChainObservation with IReactiveObject after-change. - /// + /// Verifies GenerateDeepChainObservation with IReactiveObject after-change. /// A task representing the asynchronous test operation. [Test] public async Task GenerateDeepChainObservation_ReactiveObjectAfterChange_GeneratesPropertyObservable() @@ -269,110 +247,102 @@ public async Task GenerateDeepChainObservation_ReactiveObjectAfterChange_Generat var sb = new StringBuilder(); var paths = new EquatableArray>([ new([ - ModelFactory.CreatePropertyPathSegment("Address", "global::TestApp.Address"), - ModelFactory.CreatePropertyPathSegment("City", "global::System.String", "global::TestApp.Address") + ModelFactory.CreatePropertyPathSegment(AddressName, AddressTypeName), + ModelFactory.CreatePropertyPathSegment("City", StringTypeName, AddressTypeName) ]) ]); var inv = ModelFactory.CreateInvocationInfo( propertyPaths: paths, - expressionTexts: new EquatableArray(["x => x.Address.City"])); + expressionTexts: new EquatableArray([CitySelector])); var classInfo = ModelFactory.CreateClassBindingInfo(implementsIReactiveObject: true); ObservationCodeGenerator.GenerateDeepChainObservation(sb, inv, classInfo, false); var result = sb.ToString(); - await Assert.That(result).Contains("PropertyObservable"); - await Assert.That(result).Contains("DistinctUntilChanged"); + await Assert.That(result).Contains(PropertyObservableName); + await Assert.That(result).Contains(DistinctUntilChangedName); } - /// - /// Verifies EmitInlineObservation with null classInfo generates PropertyObservable (uses null-safe path). - /// + /// Verifies EmitInlineObservation with null classInfo generates PropertyObservable (uses null-safe path). /// A task representing the asynchronous test operation. [Test] public async Task EmitInlineObservation_NullClassInfo_SingleProperty_GeneratesPropertyObservable() { var sb = new StringBuilder(); var path = new EquatableArray( - [ModelFactory.CreatePropertyPathSegment("Name")]); + [ModelFactory.CreatePropertyPathSegment()]); - ObservationCodeGenerator.EmitInlineObservation(sb, "source", path, "global::System.String", null, "sourceObs"); + ObservationCodeGenerator.EmitInlineObservation(sb, SourceName, path, StringTypeName, null, SourceObsName); var result = sb.ToString(); - await Assert.That(result).Contains("var sourceObs"); + await Assert.That(result).Contains(SourceObsDeclaration); } - /// - /// Verifies EmitInlineObservation with IReactiveObject generates PropertyObservable for single property. - /// + /// Verifies EmitInlineObservation with IReactiveObject generates PropertyObservable for single property. /// A task representing the asynchronous test operation. [Test] public async Task EmitInlineObservation_ReactiveObject_SingleProperty_GeneratesPropertyObservable() { var sb = new StringBuilder(); var path = new EquatableArray( - [ModelFactory.CreatePropertyPathSegment("Name")]); + [ModelFactory.CreatePropertyPathSegment()]); var classInfo = ModelFactory.CreateClassBindingInfo(implementsIReactiveObject: true); ObservationCodeGenerator.EmitInlineObservation( sb, - "source", + SourceName, path, - "global::System.String", + StringTypeName, classInfo, - "sourceObs"); + SourceObsName); var result = sb.ToString(); - await Assert.That(result).Contains("PropertyObservable"); + await Assert.That(result).Contains(PropertyObservableName); } - /// - /// Verifies EmitInlineObservation with IReactiveObject and deep chain generates Switch pattern. - /// + /// Verifies EmitInlineObservation with IReactiveObject and deep chain generates Switch pattern. /// A task representing the asynchronous test operation. [Test] public async Task EmitInlineObservation_ReactiveObject_DeepChain_GeneratesSwitchPattern() { var sb = new StringBuilder(); var path = new EquatableArray([ - ModelFactory.CreatePropertyPathSegment("Address", "global::TestApp.Address"), - ModelFactory.CreatePropertyPathSegment("City", "global::System.String", "global::TestApp.Address") + ModelFactory.CreatePropertyPathSegment(AddressName, AddressTypeName), + ModelFactory.CreatePropertyPathSegment("City", StringTypeName, AddressTypeName) ]); var classInfo = ModelFactory.CreateClassBindingInfo(implementsIReactiveObject: true); ObservationCodeGenerator.EmitInlineObservation( sb, - "source", + SourceName, path, - "global::System.String", + StringTypeName, classInfo, - "sourceObs"); + SourceObsName); var result = sb.ToString(); - await Assert.That(result).Contains("RxBindingExtensions.Switch("); - await Assert.That(result).Contains("PropertyObservable"); + await Assert.That(result).Contains(RxBindingExtensionsSwitchFragment); + await Assert.That(result).Contains(PropertyObservableName); } - /// - /// Verifies EmitInlineObservation with deep chain and null classInfo generates ReturnObservable fallback. - /// + /// Verifies EmitInlineObservation with deep chain and null classInfo generates ReturnObservable fallback. /// A task representing the asynchronous test operation. [Test] public async Task EmitInlineObservation_DeepChain_NullClassInfo_GeneratesReturnObservable() { var sb = new StringBuilder(); var path = new EquatableArray([ - ModelFactory.CreatePropertyPathSegment("Address", "global::TestApp.Address"), - ModelFactory.CreatePropertyPathSegment("City", "global::System.String", "global::TestApp.Address") + ModelFactory.CreatePropertyPathSegment(AddressName, AddressTypeName), + ModelFactory.CreatePropertyPathSegment("City", StringTypeName, AddressTypeName) ]); - ObservationCodeGenerator.EmitInlineObservation(sb, "source", path, "global::System.String", null, "sourceObs"); + ObservationCodeGenerator.EmitInlineObservation(sb, SourceName, path, StringTypeName, null, SourceObsName); var result = sb.ToString(); - await Assert.That(result).Contains("ReturnObservable"); + await Assert.That(result).Contains(ReturnObservableName); await Assert.That(result).Contains("__sourceObs_s0"); await Assert.That(result).Contains("__sourceObs_s1"); await Assert.That(result).Contains("Switch"); - await Assert.That(result).Contains("DistinctUntilChanged"); + await Assert.That(result).Contains(DistinctUntilChangedName); } } diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/ObservationCodeGeneratorHelperTests.MethodGeneration.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/ObservationCodeGeneratorHelperTests.MethodGeneration.cs index a041a0b..031f572 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/ObservationCodeGeneratorHelperTests.MethodGeneration.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/ObservationCodeGeneratorHelperTests.MethodGeneration.cs @@ -9,14 +9,10 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests.CodeGeneration; -/// -/// Tests for — overload, method, runtime-fallback and affinity generation. -/// +/// Tests for — overload, method, runtime-fallback and affinity generation. public partial class ObservationCodeGeneratorHelperTests { - /// - /// Verifies GenerateConcreteOverload with CallerArgExpr mode. - /// + /// Verifies GenerateConcreteOverload with CallerArgExpr mode. /// A task representing the asynchronous test operation. [Test] public async Task GenerateConcreteOverload_CallerArgExpr_GeneratesExpressionDispatch() @@ -25,16 +21,14 @@ public async Task GenerateConcreteOverload_CallerArgExpr_GeneratesExpressionDisp var inv = ModelFactory.CreateInvocationInfo(); var group = new ObservationCodeGenerator.TypeGroup(inv, [inv]); - ObservationCodeGenerator.GenerateConcreteOverload(sb, group, true, "WhenChanged"); + ObservationCodeGenerator.GenerateConcreteOverload(sb, group, true, WhenChangedName); var result = sb.ToString(); await Assert.That(result).Contains("CallerArgumentExpression"); await Assert.That(result).Contains("__WhenChanged_"); } - /// - /// Verifies GenerateConcreteOverload with CallerFilePath mode. - /// + /// Verifies GenerateConcreteOverload with CallerFilePath mode. /// A task representing the asynchronous test operation. [Test] public async Task GenerateConcreteOverload_CallerFilePath_GeneratesFilePathDispatch() @@ -43,79 +37,71 @@ public async Task GenerateConcreteOverload_CallerFilePath_GeneratesFilePathDispa var inv = ModelFactory.CreateInvocationInfo(); var group = new ObservationCodeGenerator.TypeGroup(inv, [inv]); - ObservationCodeGenerator.GenerateConcreteOverload(sb, group, false, "WhenChanged"); + ObservationCodeGenerator.GenerateConcreteOverload(sb, group, false, WhenChangedName); var result = sb.ToString(); await Assert.That(result).Contains("callerLineNumber"); await Assert.That(result).Contains("callerFilePath.EndsWith"); } - /// - /// Verifies GenerateRuntimeFallback for single property generates throw (no runtime reflection fallback). - /// + /// Verifies GenerateRuntimeFallback for single property generates throw (no runtime reflection fallback). /// A task representing the asynchronous test operation. [Test] public async Task GenerateRuntimeFallback_SingleProperty_GeneratesThrow() { var sb = new StringBuilder(); - ObservationCodeGenerator.GenerateRuntimeFallback(sb, "WhenChanged", 1, false); + ObservationCodeGenerator.GenerateRuntimeFallback(sb, WhenChangedName, 1, false); var result = sb.ToString(); - await Assert.That(result).Contains("throw new global::System.InvalidOperationException"); - await Assert.That(result).Contains("WhenChanged"); + await Assert.That(result).Contains(ThrowNewGlobalSystemInvalidOperationExceptionFragment); + await Assert.That(result).Contains(WhenChangedName); } - /// - /// Verifies GenerateRuntimeFallback for multi-property generates throw (no runtime reflection fallback). - /// + /// Verifies GenerateRuntimeFallback for multi-property generates throw (no runtime reflection fallback). /// A task representing the asynchronous test operation. [Test] public async Task GenerateRuntimeFallback_MultiPropertyWithSelector_GeneratesThrow() { + const int PropCount = 2; var sb = new StringBuilder(); - ObservationCodeGenerator.GenerateRuntimeFallback(sb, "WhenChanged", 2, true); + ObservationCodeGenerator.GenerateRuntimeFallback(sb, WhenChangedName, PropCount, true); var result = sb.ToString(); - await Assert.That(result).Contains("throw new global::System.InvalidOperationException"); - await Assert.That(result).Contains("WhenChanged"); + await Assert.That(result).Contains(ThrowNewGlobalSystemInvalidOperationExceptionFragment); + await Assert.That(result).Contains(WhenChangedName); } - /// - /// Verifies GenerateRuntimeFallback for multi-property without selector generates throw. - /// + /// Verifies GenerateRuntimeFallback for multi-property without selector generates throw. /// A task representing the asynchronous test operation. [Test] public async Task GenerateRuntimeFallback_MultiPropertyNoSelector_GeneratesThrow() { + const int PropCount = 2; var sb = new StringBuilder(); - ObservationCodeGenerator.GenerateRuntimeFallback(sb, "WhenChanged", 2, false); + ObservationCodeGenerator.GenerateRuntimeFallback(sb, WhenChangedName, PropCount, false); var result = sb.ToString(); - await Assert.That(result).Contains("throw new global::System.InvalidOperationException"); + await Assert.That(result).Contains(ThrowNewGlobalSystemInvalidOperationExceptionFragment); } - /// - /// Verifies GenerateRuntimeFallback for WhenChanging includes correct method prefix in error message. - /// + /// Verifies GenerateRuntimeFallback for WhenChanging includes correct method prefix in error message. /// A task representing the asynchronous test operation. [Test] public async Task GenerateRuntimeFallback_WhenChanging_IncludesMethodPrefixInErrorMessage() { var sb = new StringBuilder(); - ObservationCodeGenerator.GenerateRuntimeFallback(sb, "WhenChanging", 1, false); + ObservationCodeGenerator.GenerateRuntimeFallback(sb, WhenChangingName, 1, false); var result = sb.ToString(); - await Assert.That(result).Contains("throw new global::System.InvalidOperationException"); - await Assert.That(result).Contains("WhenChanging"); + await Assert.That(result).Contains(ThrowNewGlobalSystemInvalidOperationExceptionFragment); + await Assert.That(result).Contains(WhenChangingName); } - /// - /// Verifies GenerateObservationMethod with a deep chain and selector generates Switch and Select wrapping. - /// + /// Verifies GenerateObservationMethod with a deep chain and selector generates Switch and Select wrapping. /// A task representing the asynchronous test operation. [Test] public async Task GenerateObservationMethod_DeepChainWithSelector_GeneratesSwitchPattern() @@ -124,46 +110,42 @@ public async Task GenerateObservationMethod_DeepChainWithSelector_GeneratesSwitc var paths = new EquatableArray>([ new([ ModelFactory.CreatePropertyPathSegment("Address", "global::TestApp.Address"), - ModelFactory.CreatePropertyPathSegment("City", "global::System.String", "global::TestApp.Address") + ModelFactory.CreatePropertyPathSegment("City", StringTypeName, "global::TestApp.Address") ]) ]); var inv = ModelFactory.CreateInvocationInfo( propertyPaths: paths, - returnTypeFullName: "global::System.Int32", + returnTypeFullName: Int32TypeName, hasSelector: true, expressionTexts: new EquatableArray(["x => x.Address.City"])); var classInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); - ObservationCodeGenerator.GenerateObservationMethod(sb, inv, classInfo, "DEADBEEF", false, "WhenChanged"); + ObservationCodeGenerator.GenerateObservationMethod(sb, inv, classInfo, "DEADBEEF", false, WhenChangedName); var result = sb.ToString(); await Assert.That(result).Contains("RxBindingExtensions.Switch("); await Assert.That(result).Contains("__WhenChanged_DEADBEEF"); } - /// - /// Verifies GenerateObservationMethod with a single property and selector generates Select wrapping. - /// + /// Verifies GenerateObservationMethod with a single property and selector generates Select wrapping. /// A task representing the asynchronous test operation. [Test] public async Task GenerateObservationMethod_SinglePropertyWithSelector_GeneratesSelectWrap() { var sb = new StringBuilder(); var inv = ModelFactory.CreateInvocationInfo( - returnTypeFullName: "global::System.Int32", + returnTypeFullName: Int32TypeName, hasSelector: true); var classInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); - ObservationCodeGenerator.GenerateObservationMethod(sb, inv, classInfo, "CAFEBABE", false, "WhenChanged"); + ObservationCodeGenerator.GenerateObservationMethod(sb, inv, classInfo, "CAFEBABE", false, WhenChangedName); var result = sb.ToString(); await Assert.That(result).Contains("RxBindingExtensions.Select("); await Assert.That(result).Contains("selector"); } - /// - /// Verifies GenerateObservationMethod with null classInfo generates code. - /// + /// Verifies GenerateObservationMethod with null classInfo generates code. /// A task representing the asynchronous test operation. [Test] public async Task GenerateObservationMethod_NullClassInfo_GeneratesCode() @@ -171,33 +153,29 @@ public async Task GenerateObservationMethod_NullClassInfo_GeneratesCode() var sb = new StringBuilder(); var inv = ModelFactory.CreateInvocationInfo(); - ObservationCodeGenerator.GenerateObservationMethod(sb, inv, null, "DEADBEEF", false, "WhenChanged"); + ObservationCodeGenerator.GenerateObservationMethod(sb, inv, null, "DEADBEEF", false, WhenChangedName); var result = sb.ToString(); await Assert.That(result).Contains("__WhenChanged_DEADBEEF"); } - /// - /// Verifies GenerateObservationMethod single property without selector generates direct return. - /// + /// Verifies GenerateObservationMethod single property without selector generates direct return. /// A task representing the asynchronous test operation. [Test] public async Task GenerateObservationMethod_SinglePropertyNoSelector_GeneratesDirectReturn() { var sb = new StringBuilder(); - var inv = ModelFactory.CreateInvocationInfo(hasSelector: false); + var inv = ModelFactory.CreateInvocationInfo(); var classInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); - ObservationCodeGenerator.GenerateObservationMethod(sb, inv, classInfo, "ABC123", false, "WhenChanged"); + ObservationCodeGenerator.GenerateObservationMethod(sb, inv, classInfo, "ABC123", false, WhenChangedName); var result = sb.ToString(); await Assert.That(result).Contains("__WhenChanged_ABC123"); await Assert.That(result).Contains("PropertyObservable"); } - /// - /// Verifies Generate with empty invocations returns null. - /// + /// Verifies Generate with empty invocations returns null. /// A task representing the asynchronous test operation. [Test] public async Task Generate_EmptyInvocations_ReturnsNull() @@ -205,15 +183,13 @@ public async Task Generate_EmptyInvocations_ReturnsNull() var result = ObservationCodeGenerator.Generate( [], [], - new LanguageFeatures(true, true, true), - "WhenChanged"); + new(true, true, true), + WhenChangedName); await Assert.That(result).IsNull(); } - /// - /// Verifies Generate with default invocations returns null. - /// + /// Verifies Generate with default invocations returns null. /// A task representing the asynchronous test operation. [Test] public async Task Generate_DefaultInvocations_ReturnsNull() @@ -221,15 +197,13 @@ public async Task Generate_DefaultInvocations_ReturnsNull() var result = ObservationCodeGenerator.Generate( default, [], - new LanguageFeatures(true, true, true), - "WhenChanged"); + new(true, true, true), + WhenChangedName); await Assert.That(result).IsNull(); } - /// - /// Verifies Generate with valid invocations returns non-null source containing method prefix. - /// + /// Verifies Generate with valid invocations returns non-null source containing method prefix. /// A task representing the asynchronous test operation. [Test] public async Task Generate_WithInvocations_ReturnsNonNullSource() @@ -240,8 +214,8 @@ public async Task Generate_WithInvocations_ReturnsNonNullSource() var result = ObservationCodeGenerator.Generate( [inv], [classInfo], - new LanguageFeatures(true, true, true), - "WhenChanged"); + new(true, true, true), + WhenChangedName); await Assert.That(result).IsNotNull(); await Assert.That(result!).Contains("__WhenChanged_"); @@ -260,57 +234,51 @@ public async Task Generate_NoMatchingClassInfo_SkipsAffinityCheck() var result = ObservationCodeGenerator.Generate( [inv], [], - new LanguageFeatures(true, true, true), - "WhenChanged"); + new(true, true, true), + WhenChangedName); await Assert.That(result).IsNotNull(); - await Assert.That(result!).DoesNotContain("ObservationAffinityChecker"); + await Assert.That(result!).DoesNotContain(ObservationAffinityCheckerName); } - /// - /// Verifies GenerateConcreteOverload with multiple invocations in a group generates else if branching. - /// + /// Verifies GenerateConcreteOverload with multiple invocations in a group generates else if branching. /// A task representing the asynchronous test operation. [Test] public async Task GenerateConcreteOverload_MultipleInvocationsInGroup_GeneratesElseIf() { var sb = new StringBuilder(); var inv1 = ModelFactory.CreateInvocationInfo(callerLineNumber: 10, expressionTexts: new EquatableArray([ - "x => x.Name" + NameSelector ])); var inv2 = ModelFactory.CreateInvocationInfo(callerLineNumber: 20, expressionTexts: new EquatableArray([ - "x => x.Age" + AgeSelector ])); var group = new ObservationCodeGenerator.TypeGroup(inv1, [inv1, inv2]); - ObservationCodeGenerator.GenerateConcreteOverload(sb, group, true, "WhenChanged"); + ObservationCodeGenerator.GenerateConcreteOverload(sb, group, true, WhenChangedName); var result = sb.ToString(); await Assert.That(result).Contains("if ("); await Assert.That(result).Contains("else if ("); } - /// - /// Verifies GenerateConcreteOverload with selector generates selector parameter. - /// + /// Verifies GenerateConcreteOverload with selector generates selector parameter. /// A task representing the asynchronous test operation. [Test] public async Task GenerateConcreteOverload_WithSelector_GeneratesSelectorParameter() { var sb = new StringBuilder(); - var inv = ModelFactory.CreateInvocationInfo(returnTypeFullName: "global::System.Int32", hasSelector: true); + var inv = ModelFactory.CreateInvocationInfo(returnTypeFullName: Int32TypeName, hasSelector: true); var group = new ObservationCodeGenerator.TypeGroup(inv, [inv]); - ObservationCodeGenerator.GenerateConcreteOverload(sb, group, true, "WhenChanged"); + ObservationCodeGenerator.GenerateConcreteOverload(sb, group, true, WhenChangedName); var result = sb.ToString(); await Assert.That(result).Contains("Func<"); await Assert.That(result).Contains("selector"); } - /// - /// Verifies GenerateConcreteOverload with CallerArgExpr and multi-property generates multiple expression checks with AND. - /// + /// Verifies GenerateConcreteOverload with CallerArgExpr and multi-property generates multiple expression checks with AND. /// A task representing the asynchronous test operation. [Test] public async Task GenerateConcreteOverload_CallerArgExpr_MultiProperty_GeneratesMultipleExpressionChecks() @@ -318,20 +286,20 @@ public async Task GenerateConcreteOverload_CallerArgExpr_MultiProperty_Generates var sb = new StringBuilder(); var paths = new EquatableArray>([ new([ - ModelFactory.CreatePropertyPathSegment("Name", "global::System.String") + ModelFactory.CreatePropertyPathSegment() ]), new([ - ModelFactory.CreatePropertyPathSegment("Age", "global::System.Int32") + ModelFactory.CreatePropertyPathSegment("Age", Int32TypeName) ]) ]); var inv = ModelFactory.CreateInvocationInfo( propertyPaths: paths, returnTypeFullName: "(global::System.String, global::System.Int32)", hasSelector: false, - expressionTexts: new EquatableArray(["x => x.Name", "x => x.Age"])); + expressionTexts: new EquatableArray([NameSelector, AgeSelector])); var group = new ObservationCodeGenerator.TypeGroup(inv, [inv]); - ObservationCodeGenerator.GenerateConcreteOverload(sb, group, true, "WhenChanged"); + ObservationCodeGenerator.GenerateConcreteOverload(sb, group, true, WhenChangedName); var result = sb.ToString(); await Assert.That(result).Contains("property1Expression"); @@ -339,9 +307,7 @@ public async Task GenerateConcreteOverload_CallerArgExpr_MultiProperty_Generates await Assert.That(result).Contains("&&"); } - /// - /// Verifies GenerateObservationMethod generates method signature with correct prefix and suffix. - /// + /// Verifies GenerateObservationMethod generates method signature with correct prefix and suffix. /// A task representing the asynchronous test operation. [Test] public async Task GenerateObservationMethod_SingleProperty_GeneratesMethodSignature() @@ -356,7 +322,7 @@ public async Task GenerateObservationMethod_SingleProperty_GeneratesMethodSignat classInfo, "ABCDEF0123456789", false, - "WhenChanged"); + WhenChangedName); var result = sb.ToString(); await Assert.That(result).Contains("__WhenChanged_ABCDEF0123456789"); @@ -364,17 +330,16 @@ public async Task GenerateObservationMethod_SingleProperty_GeneratesMethodSignat await Assert.That(result).Contains("global::System.IObservable"); } - /// - /// Verifies EmitAffinityCheck emits HasHigherAffinityPlugin check with correct type and affinity. - /// + /// Verifies EmitAffinityCheck emits HasHigherAffinityPlugin check with correct type and affinity. /// A task representing the asynchronous test operation. [Test] public async Task EmitAffinityCheck_SingleProperty_EmitsCorrectCheck() { + const int GeneratedAffinity = 5; var sb = new StringBuilder(); var inv = ModelFactory.CreateInvocationInfo(); - ObservationCodeGenerator.EmitAffinityCheck(sb, inv, "WhenChanged", 1, false, 5); + ObservationCodeGenerator.EmitAffinityCheck(sb, inv, WhenChangedName, 1, false, GeneratedAffinity); var result = sb.ToString(); await Assert.That(result).Contains("ObservationAffinityChecker.HasHigherAffinityPlugin"); @@ -382,25 +347,22 @@ public async Task EmitAffinityCheck_SingleProperty_EmitsCorrectCheck() await Assert.That(result).Contains(", 5, false)"); } - /// - /// Verifies EmitAffinityCheck emits beforeChanged=true for WhenChanging. - /// + /// Verifies EmitAffinityCheck emits beforeChanged=true for WhenChanging. /// A task representing the asynchronous test operation. [Test] public async Task EmitAffinityCheck_WhenChanging_EmitsBeforeChangedTrue() { + const int GeneratedAffinity = 10; var sb = new StringBuilder(); var inv = ModelFactory.CreateInvocationInfo(isBeforeChange: true); - ObservationCodeGenerator.EmitAffinityCheck(sb, inv, "WhenChanging", 1, false, 10); + ObservationCodeGenerator.EmitAffinityCheck(sb, inv, WhenChangingName, 1, false, GeneratedAffinity); var result = sb.ToString(); await Assert.That(result).Contains(", 10, true)"); } - /// - /// Verifies EmitAffinityFallbackReturn emits direct RuntimeObservationFallback call for single property without selector. - /// + /// Verifies EmitAffinityFallbackReturn emits direct RuntimeObservationFallback call for single property without selector. /// A task representing the asynchronous test operation. [Test] public async Task EmitAffinityFallbackReturn_SinglePropertyNoSelector_EmitsDirectFallback() @@ -408,23 +370,21 @@ public async Task EmitAffinityFallbackReturn_SinglePropertyNoSelector_EmitsDirec var sb = new StringBuilder(); var inv = ModelFactory.CreateInvocationInfo(); - ObservationCodeGenerator.EmitAffinityFallbackReturn(sb, inv, "WhenChanged", 1, false); + ObservationCodeGenerator.EmitAffinityFallbackReturn(sb, inv, WhenChangedName, 1, false); var result = sb.ToString(); await Assert.That(result).Contains("RuntimeObservationFallback.WhenChanged(objectToMonitor, property1)"); } - /// - /// Verifies EmitAffinityFallbackReturn emits SelectObservable wrapper for single property with selector. - /// + /// Verifies EmitAffinityFallbackReturn emits SelectObservable wrapper for single property with selector. /// A task representing the asynchronous test operation. [Test] public async Task EmitAffinityFallbackReturn_SinglePropertyWithSelector_EmitsSelectObservable() { var sb = new StringBuilder(); - var inv = ModelFactory.CreateInvocationInfo(returnTypeFullName: "global::System.Int32", hasSelector: true); + var inv = ModelFactory.CreateInvocationInfo(returnTypeFullName: Int32TypeName, hasSelector: true); - ObservationCodeGenerator.EmitAffinityFallbackReturn(sb, inv, "WhenChanged", 1, true); + ObservationCodeGenerator.EmitAffinityFallbackReturn(sb, inv, WhenChangedName, 1, true); var result = sb.ToString(); await Assert.That(result).Contains("SelectObservable"); @@ -432,50 +392,48 @@ public async Task EmitAffinityFallbackReturn_SinglePropertyWithSelector_EmitsSel await Assert.That(result).Contains("selector);"); } - /// - /// Verifies EmitAffinityFallbackReturn emits multi-property fallback for two properties without selector. - /// + /// Verifies EmitAffinityFallbackReturn emits multi-property fallback for two properties without selector. /// A task representing the asynchronous test operation. [Test] public async Task EmitAffinityFallbackReturn_TwoPropertiesNoSelector_EmitsMultiPropertyFallback() { + const int PropCount = 2; var sb = new StringBuilder(); var paths = new EquatableArray>( [ - new([ModelFactory.CreatePropertyPathSegment("Name", "global::System.String")]), + new([ModelFactory.CreatePropertyPathSegment()]), new([ModelFactory.CreatePropertyPathSegment("Age", "int")]) ]); var inv = ModelFactory.CreateInvocationInfo( propertyPaths: paths, - expressionTexts: new EquatableArray(["x => x.Name", "x => x.Age"])); + expressionTexts: new EquatableArray([NameSelector, AgeSelector])); - ObservationCodeGenerator.EmitAffinityFallbackReturn(sb, inv, "WhenChanged", 2, false); + ObservationCodeGenerator.EmitAffinityFallbackReturn(sb, inv, WhenChangedName, PropCount, false); var result = sb.ToString(); await Assert.That(result) .Contains("RuntimeObservationFallback.WhenChanged(objectToMonitor, property1, property2)"); } - /// - /// Verifies EmitAffinityFallbackReturn emits tuple decomposition for multi-property with selector. - /// + /// Verifies EmitAffinityFallbackReturn emits tuple decomposition for multi-property with selector. /// A task representing the asynchronous test operation. [Test] public async Task EmitAffinityFallbackReturn_TwoPropertiesWithSelector_EmitsTupleDecomposition() { + const int PropCount = 2; var sb = new StringBuilder(); var paths = new EquatableArray>( [ - new([ModelFactory.CreatePropertyPathSegment("Name", "global::System.String")]), + new([ModelFactory.CreatePropertyPathSegment()]), new([ModelFactory.CreatePropertyPathSegment("Age", "int")]) ]); var inv = ModelFactory.CreateInvocationInfo( propertyPaths: paths, - returnTypeFullName: "global::System.String", + returnTypeFullName: StringTypeName, hasSelector: true, - expressionTexts: new EquatableArray(["x => x.Name", "x => x.Age"])); + expressionTexts: new EquatableArray([NameSelector, AgeSelector])); - ObservationCodeGenerator.EmitAffinityFallbackReturn(sb, inv, "WhenChanged", 2, true); + ObservationCodeGenerator.EmitAffinityFallbackReturn(sb, inv, WhenChangedName, PropCount, true); var result = sb.ToString(); await Assert.That(result) @@ -483,9 +441,7 @@ await Assert.That(result) await Assert.That(result).Contains("__t => selector(__t.Item1, __t.Item2)"); } - /// - /// Verifies EmitAffinityFallbackReturn emits WhenChanging fallback for before-change observation. - /// + /// Verifies EmitAffinityFallbackReturn emits WhenChanging fallback for before-change observation. /// A task representing the asynchronous test operation. [Test] public async Task EmitAffinityFallbackReturn_WhenChanging_EmitsCorrectMethodName() @@ -493,15 +449,13 @@ public async Task EmitAffinityFallbackReturn_WhenChanging_EmitsCorrectMethodName var sb = new StringBuilder(); var inv = ModelFactory.CreateInvocationInfo(isBeforeChange: true); - ObservationCodeGenerator.EmitAffinityFallbackReturn(sb, inv, "WhenChanging", 1, false); + ObservationCodeGenerator.EmitAffinityFallbackReturn(sb, inv, WhenChangingName, 1, false); var result = sb.ToString(); await Assert.That(result).Contains("RuntimeObservationFallback.WhenChanging(objectToMonitor, property1)"); } - /// - /// Verifies EmitAffinityFallbackReturn emits WhenAnyValue fallback correctly. - /// + /// Verifies EmitAffinityFallbackReturn emits WhenAnyValue fallback correctly. /// A task representing the asynchronous test operation. [Test] public async Task EmitAffinityFallbackReturn_WhenAnyValue_EmitsCorrectMethodName() @@ -515,53 +469,49 @@ public async Task EmitAffinityFallbackReturn_WhenAnyValue_EmitsCorrectMethodName await Assert.That(result).Contains("RuntimeObservationFallback.WhenAnyValue(objectToMonitor, property1)"); } - /// - /// Verifies EmitAffinityFallbackReturn emits three-property tuple decomposition with selector. - /// + /// Verifies EmitAffinityFallbackReturn emits three-property tuple decomposition with selector. /// A task representing the asynchronous test operation. [Test] public async Task EmitAffinityFallbackReturn_ThreePropertiesWithSelector_EmitsThreeItemDecomposition() { + const int PropCount = 3; var sb = new StringBuilder(); var paths = new EquatableArray>( [ - new([ModelFactory.CreatePropertyPathSegment("Name", "global::System.String")]), + new([ModelFactory.CreatePropertyPathSegment()]), new([ModelFactory.CreatePropertyPathSegment("Age", "int")]), - new([ModelFactory.CreatePropertyPathSegment("City", "global::System.String")]) + new([ModelFactory.CreatePropertyPathSegment("City")]) ]); var inv = ModelFactory.CreateInvocationInfo( propertyPaths: paths, - returnTypeFullName: "global::System.String", + returnTypeFullName: StringTypeName, hasSelector: true, - expressionTexts: new EquatableArray(["x => x.Name", "x => x.Age", "x => x.City"])); + expressionTexts: new EquatableArray([NameSelector, AgeSelector, "x => x.City"])); - ObservationCodeGenerator.EmitAffinityFallbackReturn(sb, inv, "WhenChanged", 3, true); + ObservationCodeGenerator.EmitAffinityFallbackReturn(sb, inv, WhenChangedName, PropCount, true); var result = sb.ToString(); await Assert.That(result).Contains("__t => selector(__t.Item1, __t.Item2, __t.Item3)"); } - /// - /// Verifies GenerateConcreteOverload emits affinity check when generatedAffinity is provided. - /// + /// Verifies GenerateConcreteOverload emits affinity check when generatedAffinity is provided. /// A task representing the asynchronous test operation. [Test] public async Task GenerateConcreteOverload_WithAffinity_EmitsAffinityCheck() { + const int GeneratedAffinity = 5; var sb = new StringBuilder(); var inv = ModelFactory.CreateInvocationInfo(); var group = new ObservationCodeGenerator.TypeGroup(inv, [inv]); - ObservationCodeGenerator.GenerateConcreteOverload(sb, group, true, "WhenChanged", 5); + ObservationCodeGenerator.GenerateConcreteOverload(sb, group, true, WhenChangedName, GeneratedAffinity); var result = sb.ToString(); await Assert.That(result).Contains("ObservationAffinityChecker.HasHigherAffinityPlugin"); await Assert.That(result).Contains(", 5, false)"); } - /// - /// Verifies GenerateConcreteOverload does not emit affinity check when generatedAffinity is -1. - /// + /// Verifies GenerateConcreteOverload does not emit affinity check when generatedAffinity is -1. /// A task representing the asynchronous test operation. [Test] public async Task GenerateConcreteOverload_WithoutAffinity_NoAffinityCheck() @@ -570,35 +520,34 @@ public async Task GenerateConcreteOverload_WithoutAffinity_NoAffinityCheck() var inv = ModelFactory.CreateInvocationInfo(); var group = new ObservationCodeGenerator.TypeGroup(inv, [inv]); - ObservationCodeGenerator.GenerateConcreteOverload(sb, group, true, "WhenChanged", -1); + ObservationCodeGenerator.GenerateConcreteOverload(sb, group, true, WhenChangedName); var result = sb.ToString(); - await Assert.That(result).DoesNotContain("ObservationAffinityChecker"); + await Assert.That(result).DoesNotContain(ObservationAffinityCheckerName); } - /// - /// Verifies GenerateConcreteOverload skips affinity check for more than 3 properties. - /// + /// Verifies GenerateConcreteOverload skips affinity check for more than 3 properties. /// A task representing the asynchronous test operation. [Test] public async Task GenerateConcreteOverload_FourProperties_SkipsAffinityCheck() { + const int GeneratedAffinity = 5; var sb = new StringBuilder(); var paths = new EquatableArray>( [ - new([ModelFactory.CreatePropertyPathSegment("P1", "global::System.String")]), - new([ModelFactory.CreatePropertyPathSegment("P2", "global::System.String")]), - new([ModelFactory.CreatePropertyPathSegment("P3", "global::System.String")]), - new([ModelFactory.CreatePropertyPathSegment("P4", "global::System.String")]) + new([ModelFactory.CreatePropertyPathSegment("P1")]), + new([ModelFactory.CreatePropertyPathSegment("P2")]), + new([ModelFactory.CreatePropertyPathSegment("P3")]), + new([ModelFactory.CreatePropertyPathSegment("P4")]) ]); var inv = ModelFactory.CreateInvocationInfo( propertyPaths: paths, expressionTexts: new EquatableArray(["x => x.P1", "x => x.P2", "x => x.P3", "x => x.P4"])); var group = new ObservationCodeGenerator.TypeGroup(inv, [inv]); - ObservationCodeGenerator.GenerateConcreteOverload(sb, group, true, "WhenChanged", 5); + ObservationCodeGenerator.GenerateConcreteOverload(sb, group, true, WhenChangedName, GeneratedAffinity); var result = sb.ToString(); - await Assert.That(result).DoesNotContain("ObservationAffinityChecker"); + await Assert.That(result).DoesNotContain(ObservationAffinityCheckerName); } } diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/ObservationCodeGeneratorHelperTests.MultiProperty.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/ObservationCodeGeneratorHelperTests.MultiProperty.cs index 326e89a..0411181 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/ObservationCodeGeneratorHelperTests.MultiProperty.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/ObservationCodeGeneratorHelperTests.MultiProperty.cs @@ -9,14 +9,10 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests.CodeGeneration; -/// -/// Tests for — multi-property observation. -/// +/// Tests for — multi-property observation. public partial class ObservationCodeGeneratorHelperTests { - /// - /// Verifies GenerateMultiPropertyObservation produces CombineLatest with multiple paths. - /// + /// Verifies GenerateMultiPropertyObservation produces CombineLatest with multiple paths. /// A task representing the asynchronous test operation. [Test] public async Task GenerateMultiPropertyObservation_MultiplePaths_GeneratesCombineLatest() @@ -24,30 +20,28 @@ public async Task GenerateMultiPropertyObservation_MultiplePaths_GeneratesCombin var sb = new StringBuilder(); var paths = new EquatableArray>([ new([ - ModelFactory.CreatePropertyPathSegment("Name", "global::System.String") + ModelFactory.CreatePropertyPathSegment() ]), new([ - ModelFactory.CreatePropertyPathSegment("Age", "global::System.Int32") + ModelFactory.CreatePropertyPathSegment("Age", Int32TypeName) ]) ]); var inv = ModelFactory.CreateInvocationInfo( propertyPaths: paths, - returnTypeFullName: "global::System.String", + returnTypeFullName: StringTypeName, hasSelector: true, - expressionTexts: new EquatableArray(["x => x.Name", "x => x.Age"])); + expressionTexts: new EquatableArray([NameSelector, AgeSelector])); var classInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); ObservationCodeGenerator.GenerateMultiPropertyObservation(sb, inv, classInfo, false); var result = sb.ToString(); - await Assert.That(result).Contains("CombineLatest"); + await Assert.That(result).Contains(CombineLatestName); await Assert.That(result).Contains("selector"); } - /// - /// Verifies GenerateMultiPropertyObservation with a mix of shallow and deep chain paths generates both variable styles. - /// + /// Verifies GenerateMultiPropertyObservation with a mix of shallow and deep chain paths generates both variable styles. /// A task representing the asynchronous test operation. [Test] public async Task GenerateMultiPropertyObservation_WithDeepChainPath_GeneratesDeepChainVariables() @@ -55,19 +49,19 @@ public async Task GenerateMultiPropertyObservation_WithDeepChainPath_GeneratesDe var sb = new StringBuilder(); var paths = new EquatableArray>([ new([ - ModelFactory.CreatePropertyPathSegment("Name", "global::System.String") + ModelFactory.CreatePropertyPathSegment() ]), new([ - ModelFactory.CreatePropertyPathSegment("Address", "global::TestApp.Address"), - ModelFactory.CreatePropertyPathSegment("City", "global::System.String", "global::TestApp.Address") + ModelFactory.CreatePropertyPathSegment("Address", AddressTypeName), + ModelFactory.CreatePropertyPathSegment("City", StringTypeName, AddressTypeName) ]) ]); var inv = ModelFactory.CreateInvocationInfo( propertyPaths: paths, - returnTypeFullName: "global::System.String", + returnTypeFullName: StringTypeName, hasSelector: true, - expressionTexts: new EquatableArray(["x => x.Name", "x => x.Address.City"])); + expressionTexts: new EquatableArray([NameSelector, "x => x.Address.City"])); var classInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); ObservationCodeGenerator.GenerateMultiPropertyObservation(sb, inv, classInfo, false); @@ -76,12 +70,10 @@ public async Task GenerateMultiPropertyObservation_WithDeepChainPath_GeneratesDe await Assert.That(result).Contains("__propObs0"); await Assert.That(result).Contains("__propObs1"); await Assert.That(result).Contains("RxBindingExtensions.Switch("); - await Assert.That(result).Contains("CombineLatest"); + await Assert.That(result).Contains(CombineLatestName); } - /// - /// Verifies GenerateMultiPropertyObservation with isBeforeChange=true generates PropertyChanging code. - /// + /// Verifies GenerateMultiPropertyObservation with isBeforeChange=true generates PropertyChanging code. /// A task representing the asynchronous test operation. [Test] public async Task GenerateMultiPropertyObservation_BeforeChange_GeneratesPropertyChangingCode() @@ -89,25 +81,25 @@ public async Task GenerateMultiPropertyObservation_BeforeChange_GeneratesPropert var sb = new StringBuilder(); var paths = new EquatableArray>([ new([ - ModelFactory.CreatePropertyPathSegment("Name", "global::System.String") + ModelFactory.CreatePropertyPathSegment() ]), new([ - ModelFactory.CreatePropertyPathSegment("Age", "global::System.Int32") + ModelFactory.CreatePropertyPathSegment("Age", Int32TypeName) ]) ]); var inv = ModelFactory.CreateInvocationInfo( propertyPaths: paths, - returnTypeFullName: "global::System.String", + returnTypeFullName: StringTypeName, isBeforeChange: true, hasSelector: true, - expressionTexts: new EquatableArray(["x => x.Name", "x => x.Age"])); + expressionTexts: new EquatableArray([NameSelector, AgeSelector])); var classInfo = ModelFactory.CreateClassBindingInfo(implementsINPChanging: true); ObservationCodeGenerator.GenerateMultiPropertyObservation(sb, inv, classInfo, true); var result = sb.ToString(); await Assert.That(result).Contains("PropertyChanging"); - await Assert.That(result).Contains("CombineLatest"); + await Assert.That(result).Contains(CombineLatestName); } /// @@ -120,19 +112,19 @@ public async Task GenerateMultiPropertyObservation_BeforeChange_WithDeepChain_Ge var sb = new StringBuilder(); var paths = new EquatableArray>([ new([ - ModelFactory.CreatePropertyPathSegment("Name", "global::System.String") + ModelFactory.CreatePropertyPathSegment() ]), new([ - ModelFactory.CreatePropertyPathSegment("Address", "global::TestApp.Address"), - ModelFactory.CreatePropertyPathSegment("City", "global::System.String", "global::TestApp.Address") + ModelFactory.CreatePropertyPathSegment("Address", AddressTypeName), + ModelFactory.CreatePropertyPathSegment("City", StringTypeName, AddressTypeName) ]) ]); var inv = ModelFactory.CreateInvocationInfo( propertyPaths: paths, - returnTypeFullName: "global::System.String", + returnTypeFullName: StringTypeName, isBeforeChange: true, hasSelector: true, - expressionTexts: new EquatableArray(["x => x.Name", "x => x.Address.City"])); + expressionTexts: new EquatableArray([NameSelector, "x => x.Address.City"])); var classInfo = ModelFactory.CreateClassBindingInfo(implementsINPChanging: true); ObservationCodeGenerator.GenerateMultiPropertyObservation(sb, inv, classInfo, true); @@ -140,12 +132,10 @@ public async Task GenerateMultiPropertyObservation_BeforeChange_WithDeepChain_Ge var result = sb.ToString(); await Assert.That(result).Contains("PropertyChanging"); await Assert.That(result).Contains("__propObs1_s0"); - await Assert.That(result).Contains("CombineLatest"); + await Assert.That(result).Contains(CombineLatestName); } - /// - /// Verifies GenerateMultiPropertyObservation with IReactiveObject after-change. - /// + /// Verifies GenerateMultiPropertyObservation with IReactiveObject after-change. /// A task representing the asynchronous test operation. [Test] public async Task GenerateMultiPropertyObservation_ReactiveObjectAfterChange_GeneratesPropertyObservable() @@ -153,29 +143,27 @@ public async Task GenerateMultiPropertyObservation_ReactiveObjectAfterChange_Gen var sb = new StringBuilder(); var paths = new EquatableArray>([ new([ - ModelFactory.CreatePropertyPathSegment("Name", "global::System.String") + ModelFactory.CreatePropertyPathSegment() ]), new([ - ModelFactory.CreatePropertyPathSegment("Age", "global::System.Int32") + ModelFactory.CreatePropertyPathSegment("Age", Int32TypeName) ]) ]); var inv = ModelFactory.CreateInvocationInfo( propertyPaths: paths, - returnTypeFullName: "global::System.String", + returnTypeFullName: StringTypeName, hasSelector: true, - expressionTexts: new EquatableArray(["x => x.Name", "x => x.Age"])); + expressionTexts: new EquatableArray([NameSelector, AgeSelector])); var classInfo = ModelFactory.CreateClassBindingInfo(implementsIReactiveObject: true); ObservationCodeGenerator.GenerateMultiPropertyObservation(sb, inv, classInfo, false); var result = sb.ToString(); await Assert.That(result).Contains("PropertyObservable"); - await Assert.That(result).Contains("CombineLatest"); + await Assert.That(result).Contains(CombineLatestName); } - /// - /// Verifies GenerateMultiPropertyObservation with null classInfo generates code. - /// + /// Verifies GenerateMultiPropertyObservation with null classInfo generates code. /// A task representing the asynchronous test operation. [Test] public async Task GenerateMultiPropertyObservation_NullClassInfo_GeneratesReturnObservable() @@ -183,27 +171,25 @@ public async Task GenerateMultiPropertyObservation_NullClassInfo_GeneratesReturn var sb = new StringBuilder(); var paths = new EquatableArray>([ new([ - ModelFactory.CreatePropertyPathSegment("Name", "global::System.String") + ModelFactory.CreatePropertyPathSegment() ]), new([ - ModelFactory.CreatePropertyPathSegment("Age", "global::System.Int32") + ModelFactory.CreatePropertyPathSegment("Age", Int32TypeName) ]) ]); var inv = ModelFactory.CreateInvocationInfo( propertyPaths: paths, - returnTypeFullName: "global::System.String", + returnTypeFullName: StringTypeName, hasSelector: true, - expressionTexts: new EquatableArray(["x => x.Name", "x => x.Age"])); + expressionTexts: new EquatableArray([NameSelector, AgeSelector])); ObservationCodeGenerator.GenerateMultiPropertyObservation(sb, inv, null, false); var result = sb.ToString(); - await Assert.That(result).Contains("CombineLatest"); + await Assert.That(result).Contains(CombineLatestName); } - /// - /// Verifies GenerateMultiPropertyObservation with no selector generates tuple lambda. - /// + /// Verifies GenerateMultiPropertyObservation with no selector generates tuple lambda. /// A task representing the asynchronous test operation. [Test] public async Task GenerateMultiPropertyObservation_NoSelector_GeneratesTupleResult() @@ -211,23 +197,23 @@ public async Task GenerateMultiPropertyObservation_NoSelector_GeneratesTupleResu var sb = new StringBuilder(); var paths = new EquatableArray>([ new([ - ModelFactory.CreatePropertyPathSegment("Name", "global::System.String") + ModelFactory.CreatePropertyPathSegment() ]), new([ - ModelFactory.CreatePropertyPathSegment("Age", "global::System.Int32") + ModelFactory.CreatePropertyPathSegment("Age", Int32TypeName) ]) ]); var inv = ModelFactory.CreateInvocationInfo( propertyPaths: paths, returnTypeFullName: "(global::System.String property1, global::System.Int32 property2)", hasSelector: false, - expressionTexts: new EquatableArray(["x => x.Name", "x => x.Age"])); + expressionTexts: new EquatableArray([NameSelector, AgeSelector])); var classInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); ObservationCodeGenerator.GenerateMultiPropertyObservation(sb, inv, classInfo, false); var result = sb.ToString(); - await Assert.That(result).Contains("CombineLatest"); + await Assert.That(result).Contains(CombineLatestName); await Assert.That(result).Contains("property1: p1"); await Assert.That(result).Contains("property2: p2"); } diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/ObservationCodeGeneratorHelperTests.Shallow.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/ObservationCodeGeneratorHelperTests.Shallow.cs index 15be2a5..6e28dab 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/ObservationCodeGeneratorHelperTests.Shallow.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/ObservationCodeGeneratorHelperTests.Shallow.cs @@ -9,9 +9,7 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests.CodeGeneration; -/// -/// Tests for — single-property and shallow-path observation. -/// +/// Tests for — single-property and shallow-path observation. public partial class ObservationCodeGeneratorHelperTests { /// @@ -30,13 +28,13 @@ public async Task GenerateSinglePropertyObservation_ReactiveObjectAfterChange_Ge sb, inv, classInfo, - "obj.Name", + ObjNameAccess, "Name", false); var result = sb.ToString(); - await Assert.That(result).Contains("PropertyObservable"); - await Assert.That(result).Contains("\"Name\""); + await Assert.That(result).Contains(PropertyObservableName); + await Assert.That(result).Contains(QuotedNameLiteral); await Assert.That(result).Contains("INotifyPropertyChanged"); } @@ -56,18 +54,16 @@ public async Task GenerateSinglePropertyObservation_ReactiveObjectBeforeChange_G sb, inv, classInfo, - "obj.Name", + ObjNameAccess, "Name", true); var result = sb.ToString(); - await Assert.That(result).Contains("PropertyChangingObservable"); - await Assert.That(result).Contains("\"Name\""); + await Assert.That(result).Contains(PropertyChangingObservableName); + await Assert.That(result).Contains(QuotedNameLiteral); } - /// - /// Verifies GenerateSinglePropertyObservation generates INPC after-change code. - /// + /// Verifies GenerateSinglePropertyObservation generates INPC after-change code. /// A task representing the asynchronous test operation. [Test] public async Task GenerateSinglePropertyObservation_INPCAfterChange_GeneratesPropertyChangedHandler() @@ -80,18 +76,16 @@ public async Task GenerateSinglePropertyObservation_INPCAfterChange_GeneratesPro sb, inv, classInfo, - "obj.Name", + ObjNameAccess, "Name", false); var result = sb.ToString(); - await Assert.That(result).Contains("PropertyObservable"); + await Assert.That(result).Contains(PropertyObservableName); await Assert.That(result).Contains("INotifyPropertyChanged"); } - /// - /// Verifies GenerateSinglePropertyObservation generates INPChanging before-change code. - /// + /// Verifies GenerateSinglePropertyObservation generates INPChanging before-change code. /// A task representing the asynchronous test operation. [Test] public async Task GenerateSinglePropertyObservation_INPChangingBeforeChange_GeneratesPropertyChangingHandler() @@ -104,18 +98,16 @@ public async Task GenerateSinglePropertyObservation_INPChangingBeforeChange_Gene sb, inv, classInfo, - "obj.Name", + ObjNameAccess, "Name", true); var result = sb.ToString(); - await Assert.That(result).Contains("PropertyChangingObservable"); - await Assert.That(result).Contains("INotifyPropertyChanging"); + await Assert.That(result).Contains(PropertyChangingObservableName); + await Assert.That(result).Contains(INotifyPropertyChangingName); } - /// - /// Verifies GenerateSinglePropertyObservation generates Observable.Return fallback. - /// + /// Verifies GenerateSinglePropertyObservation generates Observable.Return fallback. /// A task representing the asynchronous test operation. [Test] public async Task GenerateSinglePropertyObservation_NoInterface_GeneratesObservableReturn() @@ -128,126 +120,114 @@ public async Task GenerateSinglePropertyObservation_NoInterface_GeneratesObserva sb, inv, classInfo, - "obj.Name", + ObjNameAccess, "Name", false); var result = sb.ToString(); - await Assert.That(result).Contains("ReturnObservable"); + await Assert.That(result).Contains(ReturnObservableName); } - /// - /// Verifies GenerateShallowPathObservation for single segment delegates to single property logic. - /// + /// Verifies GenerateShallowPathObservation for single segment delegates to single property logic. /// A task representing the asynchronous test operation. [Test] public async Task GenerateShallowPathObservation_SingleSegment_GeneratesInlineObservation() { var sb = new StringBuilder(); var path = new EquatableArray( - [ModelFactory.CreatePropertyPathSegment("Name")]); + [ModelFactory.CreatePropertyPathSegment()]); var classInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); ObservationCodeGenerator.GenerateShallowPathObservation(sb, path, classInfo, false); var result = sb.ToString(); - await Assert.That(result).Contains("PropertyObservable"); - await Assert.That(result).Contains("\"Name\""); + await Assert.That(result).Contains(PropertyObservableName); + await Assert.That(result).Contains(QuotedNameLiteral); } - /// - /// Verifies GenerateShallowObservableVariable generates INPC variable for after-change. - /// + /// Verifies GenerateShallowObservableVariable generates INPC variable for after-change. /// A task representing the asynchronous test operation. [Test] public async Task GenerateShallowObservableVariable_INPCAfterChange_GeneratesVariableDeclaration() { var sb = new StringBuilder(); var path = new EquatableArray( - [ModelFactory.CreatePropertyPathSegment("Name")]); + [ModelFactory.CreatePropertyPathSegment()]); var classInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); - ObservationCodeGenerator.GenerateShallowObservableVariable(sb, path, classInfo, false, "__propObs0"); + ObservationCodeGenerator.GenerateShallowObservableVariable(sb, path, classInfo, false, PropObs0Local); var result = sb.ToString(); - await Assert.That(result).Contains("var __propObs0"); - await Assert.That(result).Contains("PropertyObservable"); + await Assert.That(result).Contains(PropObs0Declaration); + await Assert.That(result).Contains(PropertyObservableName); } - /// - /// Verifies GenerateShallowObservableVariable generates INPChanging variable for before-change. - /// + /// Verifies GenerateShallowObservableVariable generates INPChanging variable for before-change. /// A task representing the asynchronous test operation. [Test] public async Task GenerateShallowObservableVariable_INPChangingBeforeChange_GeneratesVariableDeclaration() { var sb = new StringBuilder(); var path = new EquatableArray( - [ModelFactory.CreatePropertyPathSegment("Name")]); + [ModelFactory.CreatePropertyPathSegment()]); var classInfo = ModelFactory.CreateClassBindingInfo(implementsINPChanging: true); - ObservationCodeGenerator.GenerateShallowObservableVariable(sb, path, classInfo, true, "__propObs0"); + ObservationCodeGenerator.GenerateShallowObservableVariable(sb, path, classInfo, true, PropObs0Local); var result = sb.ToString(); - await Assert.That(result).Contains("var __propObs0"); + await Assert.That(result).Contains(PropObs0Declaration); await Assert.That(result).Contains("PropertyChanging"); - await Assert.That(result).Contains("INotifyPropertyChanging"); + await Assert.That(result).Contains(INotifyPropertyChangingName); } - /// - /// Verifies GenerateShallowObservableVariable generates Observable.Return fallback. - /// + /// Verifies GenerateShallowObservableVariable generates Observable.Return fallback. /// A task representing the asynchronous test operation. [Test] public async Task GenerateShallowObservableVariable_NoInterface_GeneratesObservableReturn() { var sb = new StringBuilder(); var path = new EquatableArray( - [ModelFactory.CreatePropertyPathSegment("Name")]); + [ModelFactory.CreatePropertyPathSegment()]); var classInfo = ModelFactory.CreateClassBindingInfo(); - ObservationCodeGenerator.GenerateShallowObservableVariable(sb, path, classInfo, false, "__propObs0"); + ObservationCodeGenerator.GenerateShallowObservableVariable(sb, path, classInfo, false, PropObs0Local); var result = sb.ToString(); - await Assert.That(result).Contains("var __propObs0"); - await Assert.That(result).Contains("ReturnObservable"); + await Assert.That(result).Contains(PropObs0Declaration); + await Assert.That(result).Contains(ReturnObservableName); } - /// - /// Verifies GenerateShallowPathObservation for before-change produces PropertyChanging code. - /// + /// Verifies GenerateShallowPathObservation for before-change produces PropertyChanging code. /// A task representing the asynchronous test operation. [Test] public async Task GenerateShallowPathObservation_BeforeChange_GeneratesPropertyChangingCode() { var sb = new StringBuilder(); var path = new EquatableArray( - [ModelFactory.CreatePropertyPathSegment("Name")]); + [ModelFactory.CreatePropertyPathSegment()]); var classInfo = ModelFactory.CreateClassBindingInfo(implementsINPChanging: true); ObservationCodeGenerator.GenerateShallowPathObservation(sb, path, classInfo, true); var result = sb.ToString(); await Assert.That(result).Contains("PropertyChanging"); - await Assert.That(result).Contains("INotifyPropertyChanging"); + await Assert.That(result).Contains(INotifyPropertyChangingName); } - /// - /// Verifies GenerateShallowPathObservation with no interface generates Observable.Return. - /// + /// Verifies GenerateShallowPathObservation with no interface generates Observable.Return. /// A task representing the asynchronous test operation. [Test] public async Task GenerateShallowPathObservation_NoInterface_GeneratesObservableReturn() { var sb = new StringBuilder(); var path = new EquatableArray( - [ModelFactory.CreatePropertyPathSegment("Name")]); + [ModelFactory.CreatePropertyPathSegment()]); var classInfo = ModelFactory.CreateClassBindingInfo(); ObservationCodeGenerator.GenerateShallowPathObservation(sb, path, classInfo, false); var result = sb.ToString(); - await Assert.That(result).Contains("ReturnObservable"); + await Assert.That(result).Contains(ReturnObservableName); } /// @@ -260,12 +240,12 @@ public async Task GenerateShallowPathObservation_NullClassInfo_GeneratesObservab { var sb = new StringBuilder(); var path = new EquatableArray( - [ModelFactory.CreatePropertyPathSegment("Name")]); + [ModelFactory.CreatePropertyPathSegment()]); ObservationCodeGenerator.GenerateShallowPathObservation(sb, path, null, false); var result = sb.ToString(); - await Assert.That(result).Contains("ReturnObservable"); + await Assert.That(result).Contains(ReturnObservableName); } /// @@ -278,83 +258,75 @@ public async Task GenerateShallowPathObservation_ReactiveObjectAfterChange_Gener { var sb = new StringBuilder(); var path = new EquatableArray( - [ModelFactory.CreatePropertyPathSegment("Name")]); + [ModelFactory.CreatePropertyPathSegment()]); var classInfo = ModelFactory.CreateClassBindingInfo(implementsIReactiveObject: true); ObservationCodeGenerator.GenerateShallowPathObservation(sb, path, classInfo, false); var result = sb.ToString(); - await Assert.That(result).Contains("PropertyObservable"); + await Assert.That(result).Contains(PropertyObservableName); } - /// - /// Verifies GenerateShallowPathObservation with IReactiveObject before-change generates PropertyChangingObservable. - /// + /// Verifies GenerateShallowPathObservation with IReactiveObject before-change generates PropertyChangingObservable. /// A task representing the asynchronous test operation. [Test] public async Task GenerateShallowPathObservation_ReactiveObjectBeforeChange_GeneratesPropertyChangingObservable() { var sb = new StringBuilder(); var path = new EquatableArray( - [ModelFactory.CreatePropertyPathSegment("Name")]); + [ModelFactory.CreatePropertyPathSegment()]); var classInfo = ModelFactory.CreateClassBindingInfo(implementsIReactiveObject: true); ObservationCodeGenerator.GenerateShallowPathObservation(sb, path, classInfo, true); var result = sb.ToString(); - await Assert.That(result).Contains("PropertyChangingObservable"); + await Assert.That(result).Contains(PropertyChangingObservableName); } - /// - /// Verifies GenerateShallowObservableVariable with null classInfo generates ReturnObservable. - /// + /// Verifies GenerateShallowObservableVariable with null classInfo generates ReturnObservable. /// A task representing the asynchronous test operation. [Test] public async Task GenerateShallowObservableVariable_NullClassInfo_GeneratesReturnObservable() { var sb = new StringBuilder(); var path = new EquatableArray( - [ModelFactory.CreatePropertyPathSegment("Name")]); + [ModelFactory.CreatePropertyPathSegment()]); - ObservationCodeGenerator.GenerateShallowObservableVariable(sb, path, null, false, "__obs0"); + ObservationCodeGenerator.GenerateShallowObservableVariable(sb, path, null, false, Obs0Local); var result = sb.ToString(); - await Assert.That(result).Contains("ReturnObservable"); + await Assert.That(result).Contains(ReturnObservableName); } - /// - /// Verifies GenerateShallowObservableVariable with IReactiveObject after-change generates PropertyObservable. - /// + /// Verifies GenerateShallowObservableVariable with IReactiveObject after-change generates PropertyObservable. /// A task representing the asynchronous test operation. [Test] public async Task GenerateShallowObservableVariable_ReactiveObjectAfterChange_GeneratesPropertyObservable() { var sb = new StringBuilder(); var path = new EquatableArray( - [ModelFactory.CreatePropertyPathSegment("Name")]); + [ModelFactory.CreatePropertyPathSegment()]); var classInfo = ModelFactory.CreateClassBindingInfo(implementsIReactiveObject: true); - ObservationCodeGenerator.GenerateShallowObservableVariable(sb, path, classInfo, false, "__obs0"); + ObservationCodeGenerator.GenerateShallowObservableVariable(sb, path, classInfo, false, Obs0Local); var result = sb.ToString(); - await Assert.That(result).Contains("PropertyObservable"); + await Assert.That(result).Contains(PropertyObservableName); } - /// - /// Verifies GenerateShallowObservableVariable with IReactiveObject before-change generates PropertyChangingObservable. - /// + /// Verifies GenerateShallowObservableVariable with IReactiveObject before-change generates PropertyChangingObservable. /// A task representing the asynchronous test operation. [Test] public async Task GenerateShallowObservableVariable_ReactiveObjectBeforeChange_GeneratesPropertyChangingObservable() { var sb = new StringBuilder(); var path = new EquatableArray( - [ModelFactory.CreatePropertyPathSegment("Name")]); + [ModelFactory.CreatePropertyPathSegment()]); var classInfo = ModelFactory.CreateClassBindingInfo(implementsIReactiveObject: true); - ObservationCodeGenerator.GenerateShallowObservableVariable(sb, path, classInfo, true, "__obs0"); + ObservationCodeGenerator.GenerateShallowObservableVariable(sb, path, classInfo, true, Obs0Local); var result = sb.ToString(); - await Assert.That(result).Contains("PropertyChangingObservable"); + await Assert.That(result).Contains(PropertyChangingObservableName); } } diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/ObservationCodeGeneratorHelperTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/ObservationCodeGeneratorHelperTests.cs index 52403d6..10c3f99 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/ObservationCodeGeneratorHelperTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/ObservationCodeGeneratorHelperTests.cs @@ -10,20 +10,97 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests.CodeGeneration; -/// -/// Tests for helper methods. -/// +/// Tests for helper methods. public partial class ObservationCodeGeneratorHelperTests { - /// - /// Verifies GetSelectorType returns correct Func type for single-property invocation. - /// + /// The fully qualified name of the String type used by these tests. + private const string StringTypeName = "global::System.String"; + + /// The fully qualified name of the Int32 type used by these tests. + private const string Int32TypeName = "global::System.Int32"; + + /// The fully qualified name of the Address type used by these tests. + private const string AddressTypeName = "global::TestApp.Address"; + + /// The Address name these tests generate against. + private const string AddressName = "Address"; + + /// The DistinctUntilChanged name these tests generate against. + private const string DistinctUntilChangedName = "DistinctUntilChanged"; + + /// The CombineLatest name these tests generate against. + private const string CombineLatestName = "CombineLatest"; + + /// The INotifyPropertyChanging name these tests generate against. + private const string INotifyPropertyChangingName = "INotifyPropertyChanging"; + + /// The ObservationAffinityChecker name these tests generate against. + private const string ObservationAffinityCheckerName = "ObservationAffinityChecker"; + + /// The PropertyObservable name these tests generate against. + private const string PropertyObservableName = "PropertyObservable"; + + /// The PropertyChangingObservable name these tests generate against. + private const string PropertyChangingObservableName = "PropertyChangingObservable"; + + /// The ReturnObservable name these tests generate against. + private const string ReturnObservableName = "ReturnObservable"; + + /// The WhenChanged name these tests generate against. + private const string WhenChangedName = "WhenChanged"; + + /// The WhenChanging name these tests generate against. + private const string WhenChangingName = "WhenChanging"; + + /// The source name these tests generate against. + private const string SourceName = "source"; + + /// The sourceObs name these tests generate against. + private const string SourceObsName = "sourceObs"; + + /// The var sourceObs local the generated code is expected to emit. + private const string SourceObsDeclaration = "var sourceObs"; + + /// The __obs0 local the generated code is expected to emit. + private const string Obs0Local = "__obs0"; + + /// The __propObs0 local the generated code is expected to emit. + private const string PropObs0Local = "__propObs0"; + + /// The var __propObs0 local the generated code is expected to emit. + private const string PropObs0Declaration = "var __propObs0"; + + /// The quoted Name property-name argument the generated code is expected to emit. + private const string QuotedNameLiteral = "\"Name\""; + + /// The obj.Name property access the generated code is expected to emit. + private const string ObjNameAccess = "obj.Name"; + + /// The x => x.Name property selector these tests bind against. + private const string NameSelector = "x => x.Name"; + + /// The x => x.Age property selector these tests bind against. + private const string AgeSelector = "x => x.Age"; + + /// The x => x.Address.City property selector these tests bind against. + private const string CitySelector = "x => x.Address.City"; + + /// The RxBindingExtensions.DistinctUntilChanged( fragment these tests expect in the generated source. + private const string RxBindingExtensionsDistinctUntilChangedFragment = "RxBindingExtensions.DistinctUntilChanged("; + + /// The RxBindingExtensions.Switch( fragment these tests expect in the generated source. + private const string RxBindingExtensionsSwitchFragment = "RxBindingExtensions.Switch("; + + /// The throw new global::System.InvalidOperationException fragment these tests expect in the generated source. + private const string ThrowNewGlobalSystemInvalidOperationExceptionFragment = "throw new global::System.InvalidOperationException"; + + /// Verifies GetSelectorType returns correct Func type for single-property invocation. /// A task representing the asynchronous test operation. [Test] public async Task GetSelectorType_SingleProperty_ReturnsFuncType() { var inv = ModelFactory.CreateInvocationInfo( - returnTypeFullName: "global::System.String", + returnTypeFullName: StringTypeName, hasSelector: true); var result = ObservationCodeGenerator.GetSelectorType(inv); @@ -31,16 +108,14 @@ public async Task GetSelectorType_SingleProperty_ReturnsFuncType() await Assert.That(result).IsEqualTo("global::System.Func"); } - /// - /// Verifies GetSelectorType returns correct Func type for multi-property invocation. - /// + /// Verifies GetSelectorType returns correct Func type for multi-property invocation. /// A task representing the asynchronous test operation. [Test] public async Task GetSelectorType_MultiProperty_ReturnsFuncType() { var paths = new EquatableArray>([ new([ - ModelFactory.CreatePropertyPathSegment("Name", "global::System.String") + ModelFactory.CreatePropertyPathSegment() ]), new([ ModelFactory.CreatePropertyPathSegment("Age", "global::System.Int32") @@ -49,7 +124,7 @@ public async Task GetSelectorType_MultiProperty_ReturnsFuncType() var inv = ModelFactory.CreateInvocationInfo( propertyPaths: paths, - returnTypeFullName: "global::System.String", + returnTypeFullName: StringTypeName, hasSelector: true, expressionTexts: new EquatableArray(["x => x.Name", "x => x.Age"])); @@ -59,13 +134,12 @@ await Assert.That(result) .IsEqualTo("global::System.Func"); } - /// - /// Verifies GroupByTypeSignature groups invocations with the same source and return types. - /// + /// Verifies GroupByTypeSignature groups invocations with the same source and return types. /// A task representing the asynchronous test operation. [Test] public async Task GroupByTypeSignature_SameSignature_GroupedTogether() { + const int ExpectedInvocationCount = 2; var inv1 = ModelFactory.CreateInvocationInfo(callerLineNumber: 10); var inv2 = ModelFactory.CreateInvocationInfo(callerLineNumber: 20); var invocations = ImmutableArray.Create(inv1, inv2); @@ -73,28 +147,25 @@ public async Task GroupByTypeSignature_SameSignature_GroupedTogether() var groups = ObservationCodeGenerator.GroupByTypeSignature(invocations); await Assert.That(groups.Count).IsEqualTo(1); - await Assert.That(groups[0].Invocations.Length).IsEqualTo(2); + await Assert.That(groups[0].Invocations.Length).IsEqualTo(ExpectedInvocationCount); } - /// - /// Verifies GroupByTypeSignature separates invocations with different return types. - /// + /// Verifies GroupByTypeSignature separates invocations with different return types. /// A task representing the asynchronous test operation. [Test] public async Task GroupByTypeSignature_DifferentReturnTypes_SeparateGroups() { - var inv1 = ModelFactory.CreateInvocationInfo(returnTypeFullName: "global::System.String"); + const int ExpectedGroupCount = 2; + var inv1 = ModelFactory.CreateInvocationInfo(); var inv2 = ModelFactory.CreateInvocationInfo(returnTypeFullName: "global::System.Int32"); var invocations = ImmutableArray.Create(inv1, inv2); var groups = ObservationCodeGenerator.GroupByTypeSignature(invocations); - await Assert.That(groups.Count).IsEqualTo(2); + await Assert.That(groups.Count).IsEqualTo(ExpectedGroupCount); } - /// - /// Verifies GenerateMultiPropertyObservation with deep chain and IReactiveObject before-change. - /// + /// Verifies GenerateMultiPropertyObservation with deep chain and IReactiveObject before-change. /// A task representing the asynchronous test operation. [Test] public async Task @@ -103,16 +174,16 @@ public async Task var sb = new StringBuilder(); var paths = new EquatableArray>([ new([ - ModelFactory.CreatePropertyPathSegment("Name", "global::System.String") + ModelFactory.CreatePropertyPathSegment() ]), new([ ModelFactory.CreatePropertyPathSegment("Address", "global::TestApp.Address"), - ModelFactory.CreatePropertyPathSegment("City", "global::System.String", "global::TestApp.Address") + ModelFactory.CreatePropertyPathSegment("City", StringTypeName, "global::TestApp.Address") ]) ]); var inv = ModelFactory.CreateInvocationInfo( propertyPaths: paths, - returnTypeFullName: "global::System.String", + returnTypeFullName: StringTypeName, isBeforeChange: true, hasSelector: true, expressionTexts: new EquatableArray(["x => x.Name", "x => x.Address.City"])); @@ -125,9 +196,7 @@ public async Task await Assert.That(result).Contains("CombineLatest"); } - /// - /// Verifies IsINPC returns true when classInfo implements IReactiveObject. - /// + /// Verifies IsINPC returns true when classInfo implements IReactiveObject. /// A task representing the asynchronous test operation. [Test] public async Task IsINPC_ReactiveObject_ReturnsTrue() @@ -136,9 +205,7 @@ public async Task IsINPC_ReactiveObject_ReturnsTrue() await Assert.That(ObservationCodeGenerator.IsINPC(classInfo)).IsTrue(); } - /// - /// Verifies IsINPC returns true when classInfo implements INPC directly. - /// + /// Verifies IsINPC returns true when classInfo implements INPC directly. /// A task representing the asynchronous test operation. [Test] public async Task IsINPC_DirectINPC_ReturnsTrue() @@ -147,9 +214,7 @@ public async Task IsINPC_DirectINPC_ReturnsTrue() await Assert.That(ObservationCodeGenerator.IsINPC(classInfo)).IsTrue(); } - /// - /// Verifies IsINPC returns false when classInfo has no INPC support. - /// + /// Verifies IsINPC returns false when classInfo has no INPC support. /// A task representing the asynchronous test operation. [Test] public async Task IsINPC_NoINPC_ReturnsFalse() @@ -158,17 +223,13 @@ public async Task IsINPC_NoINPC_ReturnsFalse() await Assert.That(ObservationCodeGenerator.IsINPC(classInfo)).IsFalse(); } - /// - /// Verifies IsINPC returns false when classInfo is null. - /// + /// Verifies IsINPC returns false when classInfo is null. /// A task representing the asynchronous test operation. [Test] public async Task IsINPC_NullClassInfo_ReturnsFalse() => await Assert.That(ObservationCodeGenerator.IsINPC(null)).IsFalse(); - /// - /// Verifies IsINPChanging returns true when classInfo implements IReactiveObject. - /// + /// Verifies IsINPChanging returns true when classInfo implements IReactiveObject. /// A task representing the asynchronous test operation. [Test] public async Task IsINPChanging_ReactiveObject_ReturnsTrue() @@ -177,9 +238,7 @@ public async Task IsINPChanging_ReactiveObject_ReturnsTrue() await Assert.That(ObservationCodeGenerator.IsINPChanging(classInfo)).IsTrue(); } - /// - /// Verifies IsINPChanging returns true when classInfo implements INPChanging directly. - /// + /// Verifies IsINPChanging returns true when classInfo implements INPChanging directly. /// A task representing the asynchronous test operation. [Test] public async Task IsINPChanging_DirectINPChanging_ReturnsTrue() @@ -188,9 +247,7 @@ public async Task IsINPChanging_DirectINPChanging_ReturnsTrue() await Assert.That(ObservationCodeGenerator.IsINPChanging(classInfo)).IsTrue(); } - /// - /// Verifies IsINPChanging returns false when classInfo has no INPChanging support. - /// + /// Verifies IsINPChanging returns false when classInfo has no INPChanging support. /// A task representing the asynchronous test operation. [Test] public async Task IsINPChanging_NoINPChanging_ReturnsFalse() @@ -199,17 +256,13 @@ public async Task IsINPChanging_NoINPChanging_ReturnsFalse() await Assert.That(ObservationCodeGenerator.IsINPChanging(classInfo)).IsFalse(); } - /// - /// Verifies IsINPChanging returns false when classInfo is null. - /// + /// Verifies IsINPChanging returns false when classInfo is null. /// A task representing the asynchronous test operation. [Test] public async Task IsINPChanging_NullClassInfo_ReturnsFalse() => await Assert.That(ObservationCodeGenerator.IsINPChanging(null)).IsFalse(); - /// - /// Verifies GetTypeCastName returns the fully qualified name when classInfo is provided. - /// + /// Verifies GetTypeCastName returns the fully qualified name when classInfo is provided. /// A task representing the asynchronous test operation. [Test] public async Task GetTypeCastName_WithClassInfo_ReturnsFullyQualifiedName() @@ -219,9 +272,7 @@ public async Task GetTypeCastName_WithClassInfo_ReturnsFullyQualifiedName() await Assert.That(result).IsEqualTo(classInfo.FullyQualifiedName); } - /// - /// Verifies GetTypeCastName returns "object" when classInfo is null. - /// + /// Verifies GetTypeCastName returns "object" when classInfo is null. /// A task representing the asynchronous test operation. [Test] public async Task GetTypeCastName_NullClassInfo_ReturnsObject() diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/OneWayBindCodeGeneratorHelperTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/OneWayBindCodeGeneratorHelperTests.cs index 03ac614..4d56dde 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/OneWayBindCodeGeneratorHelperTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/OneWayBindCodeGeneratorHelperTests.cs @@ -10,60 +10,72 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests.CodeGeneration; -/// -/// Tests for helper methods. -/// +/// Tests for helper methods. public class OneWayBindCodeGeneratorHelperTests { - /// - /// Verifies GroupByTypeSignature groups invocations with the same type signature. - /// + /// The fully qualified name of the Int32 type used by these tests. + private const string Int32TypeName = "global::System.Int32"; + + /// The fully qualified name of the String type used by these tests. + private const string StringTypeName = "global::System.String"; + + /// The fully qualified name of the View type used by these tests. + private const string ViewTypeName = "global::TestApp.View"; + + /// The fully qualified name of the VM type used by these tests. + private const string VMTypeName = "global::TestApp.VM"; + + /// The IReactiveBinding name these tests generate against. + private const string IReactiveBindingName = "IReactiveBinding"; + + /// The OneWayBind name these tests generate against. + private const string OneWayBindName = "OneWayBind"; + + /// Verifies GroupByTypeSignature groups invocations with the same type signature. /// A task representing the asynchronous test operation. [Test] public async Task GroupByTypeSignature_SameSignature_GroupedTogether() { - var inv1 = ModelFactory.CreateBindingInvocationInfo(callerLineNumber: 10, methodName: "OneWayBind"); - var inv2 = ModelFactory.CreateBindingInvocationInfo(callerLineNumber: 20, methodName: "OneWayBind"); + const int ExpectedInvocationCount = 2; + var inv1 = ModelFactory.CreateBindingInvocationInfo(callerLineNumber: 10, methodName: OneWayBindName); + var inv2 = ModelFactory.CreateBindingInvocationInfo(callerLineNumber: 20, methodName: OneWayBindName); var invocations = ImmutableArray.Create(inv1, inv2); var groups = OneWayBindCodeGenerator.GroupByTypeSignature(invocations); await Assert.That(groups.Count).IsEqualTo(1); - await Assert.That(groups[0].Invocations.Length).IsEqualTo(2); + await Assert.That(groups[0].Invocations.Length).IsEqualTo(ExpectedInvocationCount); } - /// - /// Verifies GroupByTypeSignature separates invocations with different target types. - /// + /// Verifies GroupByTypeSignature separates invocations with different target types. /// A task representing the asynchronous test operation. [Test] public async Task GroupByTypeSignature_DifferentTargetTypes_SeparateGroups() { + const int ExpectedGroupCount = 2; var inv1 = ModelFactory.CreateBindingInvocationInfo( targetTypeFullName: "global::TestApp.ViewA", - methodName: "OneWayBind"); + methodName: OneWayBindName); var inv2 = ModelFactory.CreateBindingInvocationInfo( targetTypeFullName: "global::TestApp.ViewB", - methodName: "OneWayBind"); + methodName: OneWayBindName); var invocations = ImmutableArray.Create(inv1, inv2); var groups = OneWayBindCodeGenerator.GroupByTypeSignature(invocations); - await Assert.That(groups.Count).IsEqualTo(2); + await Assert.That(groups.Count).IsEqualTo(ExpectedGroupCount); } - /// - /// Verifies FormatExtraArgs returns empty when no conversion or scheduler. - /// + /// Verifies FormatExtraArgs returns empty when no conversion or scheduler. /// A task representing the asynchronous test operation. [Test] public async Task FormatExtraArgs_NoConversionNoScheduler_ReturnsEmpty() { var group = new OneWayBindCodeGenerator.BindingTypeGroup( - "global::TestApp.VM", - "global::TestApp.View", - "global::System.String", - "global::System.String", + VMTypeName, + ViewTypeName, + StringTypeName, + StringTypeName, false, false, []); @@ -73,18 +85,16 @@ public async Task FormatExtraArgs_NoConversionNoScheduler_ReturnsEmpty() await Assert.That(result).IsEqualTo(string.Empty); } - /// - /// Verifies FormatExtraArgs includes selector when HasConversion is true. - /// + /// Verifies FormatExtraArgs includes selector when HasConversion is true. /// A task representing the asynchronous test operation. [Test] public async Task FormatExtraArgs_WithConversion_IncludesSelectorArg() { var group = new OneWayBindCodeGenerator.BindingTypeGroup( - "global::TestApp.VM", - "global::TestApp.View", - "global::System.String", - "global::System.String", + VMTypeName, + ViewTypeName, + StringTypeName, + StringTypeName, true, false, []); @@ -94,18 +104,16 @@ public async Task FormatExtraArgs_WithConversion_IncludesSelectorArg() await Assert.That(result).Contains("selector"); } - /// - /// Verifies FormatExtraArgs includes scheduler when HasScheduler is true. - /// + /// Verifies FormatExtraArgs includes scheduler when HasScheduler is true. /// A task representing the asynchronous test operation. [Test] public async Task FormatExtraArgs_WithScheduler_IncludesSchedulerArg() { var group = new OneWayBindCodeGenerator.BindingTypeGroup( - "global::TestApp.VM", - "global::TestApp.View", - "global::System.String", - "global::System.String", + VMTypeName, + ViewTypeName, + StringTypeName, + StringTypeName, false, true, []); @@ -115,70 +123,62 @@ public async Task FormatExtraArgs_WithScheduler_IncludesSchedulerArg() await Assert.That(result).Contains("scheduler"); } - /// - /// Verifies FormatReturnType without conversion uses source property type. - /// + /// Verifies FormatReturnType without conversion uses source property type. /// A task representing the asynchronous test operation. [Test] public async Task FormatReturnType_NoConversion_UsesSourcePropertyType() { var group = new OneWayBindCodeGenerator.BindingTypeGroup( - "global::TestApp.VM", - "global::TestApp.View", - "global::System.Int32", - "global::System.String", + VMTypeName, + ViewTypeName, + Int32TypeName, + StringTypeName, false, false, []); var result = OneWayBindCodeGenerator.FormatReturnType(group); - await Assert.That(result).Contains("IReactiveBinding"); - await Assert.That(result).Contains("global::System.Int32"); + await Assert.That(result).Contains(IReactiveBindingName); + await Assert.That(result).Contains(Int32TypeName); } - /// - /// Verifies FormatReturnType with conversion uses target property type. - /// + /// Verifies FormatReturnType with conversion uses target property type. /// A task representing the asynchronous test operation. [Test] public async Task FormatReturnType_WithConversion_UsesTargetPropertyType() { var group = new OneWayBindCodeGenerator.BindingTypeGroup( - "global::TestApp.VM", - "global::TestApp.View", - "global::System.Int32", - "global::System.String", + VMTypeName, + ViewTypeName, + Int32TypeName, + StringTypeName, true, false, []); var result = OneWayBindCodeGenerator.FormatReturnType(group); - await Assert.That(result).Contains("IReactiveBinding"); - await Assert.That(result).Contains("global::System.String"); + await Assert.That(result).Contains(IReactiveBindingName); + await Assert.That(result).Contains(StringTypeName); } - /// - /// Verifies FormatMethodReturnType uses target property type. - /// + /// Verifies FormatMethodReturnType uses target property type. /// A task representing the asynchronous test operation. [Test] public async Task FormatMethodReturnType_ReturnsTargetPropertyType() { var inv = ModelFactory.CreateBindingInvocationInfo( - targetPropertyTypeFullName: "global::System.Int32", - methodName: "OneWayBind"); + targetPropertyTypeFullName: Int32TypeName, + methodName: OneWayBindName); var result = OneWayBindCodeGenerator.FormatMethodReturnType(inv); - await Assert.That(result).Contains("IReactiveBinding"); - await Assert.That(result).Contains("global::System.Int32"); + await Assert.That(result).Contains(IReactiveBindingName); + await Assert.That(result).Contains(Int32TypeName); } - /// - /// Verifies FormatExtraMethodParams returns empty when no conversion or scheduler. - /// + /// Verifies FormatExtraMethodParams returns empty when no conversion or scheduler. /// A task representing the asynchronous test operation. [Test] public async Task FormatExtraMethodParams_NoConversionNoScheduler_ReturnsEmpty() @@ -186,21 +186,19 @@ public async Task FormatExtraMethodParams_NoConversionNoScheduler_ReturnsEmpty() var inv = ModelFactory.CreateBindingInvocationInfo( hasConversion: false, hasScheduler: false, - methodName: "OneWayBind"); + methodName: OneWayBindName); var result = OneWayBindCodeGenerator.FormatExtraMethodParams(inv); await Assert.That(result).IsEqualTo(string.Empty); } - /// - /// Verifies FormatExtraMethodParams includes Func selector when HasConversion is true. - /// + /// Verifies FormatExtraMethodParams includes Func selector when HasConversion is true. /// A task representing the asynchronous test operation. [Test] public async Task FormatExtraMethodParams_WithConversion_IncludesFuncSelector() { - var inv = ModelFactory.CreateBindingInvocationInfo(hasConversion: true, methodName: "OneWayBind"); + var inv = ModelFactory.CreateBindingInvocationInfo(hasConversion: true, methodName: OneWayBindName); var result = OneWayBindCodeGenerator.FormatExtraMethodParams(inv); @@ -208,20 +206,18 @@ public async Task FormatExtraMethodParams_WithConversion_IncludesFuncSelector() await Assert.That(result).Contains("selector"); } - /// - /// Verifies GenerateConcreteOverload with CallerArgExpr generates expression dispatch. - /// + /// Verifies GenerateConcreteOverload with CallerArgExpr generates expression dispatch. /// A task representing the asynchronous test operation. [Test] public async Task GenerateConcreteOverload_CallerArgExpr_GeneratesExpressionDispatch() { var sb = new StringBuilder(); - var inv = ModelFactory.CreateBindingInvocationInfo(methodName: "OneWayBind"); + var inv = ModelFactory.CreateBindingInvocationInfo(methodName: OneWayBindName); var group = new OneWayBindCodeGenerator.BindingTypeGroup( "global::TestApp.MyViewModel", "global::TestApp.MyView", - "global::System.String", - "global::System.String", + StringTypeName, + StringTypeName, false, false, [inv]); @@ -233,15 +229,13 @@ public async Task GenerateConcreteOverload_CallerArgExpr_GeneratesExpressionDisp await Assert.That(result).Contains("__OneWayBind_"); } - /// - /// Verifies GenerateOneWayBindMethod generates PropertyObservable + Subscribe + ReactiveBinding. - /// + /// Verifies GenerateOneWayBindMethod generates PropertyObservable + Subscribe + ReactiveBinding. /// A task representing the asynchronous test operation. [Test] public async Task GenerateOneWayBindMethod_StandardInvocation_GeneratesReactiveBinding() { var sb = new StringBuilder(); - var inv = ModelFactory.CreateBindingInvocationInfo(methodName: "OneWayBind"); + var inv = ModelFactory.CreateBindingInvocationInfo(methodName: OneWayBindName); var classInfo = ModelFactory.CreateClassBindingInfo(implementsINPC: true); OneWayBindCodeGenerator.GenerateOneWayBindMethod(sb, inv, classInfo, "TEST00000000TEST"); diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/WhenChangingCodeGeneratorHelperTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/WhenChangingCodeGeneratorHelperTests.cs index 8d21bbd..11ae43b 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/WhenChangingCodeGeneratorHelperTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/CodeGeneration/WhenChangingCodeGeneratorHelperTests.cs @@ -9,41 +9,43 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests.CodeGeneration; -/// -/// Tests for helper methods exercised via WhenChanging scenarios. -/// +/// Tests for helper methods exercised via WhenChanging scenarios. public class WhenChangingCodeGeneratorHelperTests { - /// - /// Verifies GroupByTypeSignature groups invocations with the same source and return types. - /// + /// The WhenChanging name these tests generate against. + private const string WhenChangingName = "WhenChanging"; + + /// The __WhenChanging_ local the generated code is expected to emit. + private const string WhenChangingLocal = "__WhenChanging_"; + + /// Verifies GroupByTypeSignature groups invocations with the same source and return types. /// A task representing the asynchronous test operation. [Test] public async Task GroupByTypeSignature_SameTypes_GroupedTogether() { + const int ExpectedInvocationCount = 2; var inv1 = ModelFactory.CreateInvocationInfo( callerLineNumber: 10, isBeforeChange: true, - methodName: "WhenChanging"); + methodName: WhenChangingName); var inv2 = ModelFactory.CreateInvocationInfo( callerLineNumber: 20, isBeforeChange: true, - methodName: "WhenChanging"); + methodName: WhenChangingName); var invocations = ImmutableArray.Create(inv1, inv2); var groups = ObservationCodeGenerator.GroupByTypeSignature(invocations); await Assert.That(groups.Count).IsEqualTo(1); - await Assert.That(groups[0].Invocations.Length).IsEqualTo(2); + await Assert.That(groups[0].Invocations.Length).IsEqualTo(ExpectedInvocationCount); } - /// - /// Verifies GroupByTypeSignature separates invocations with different source types. - /// + /// Verifies GroupByTypeSignature separates invocations with different source types. /// A task representing the asynchronous test operation. [Test] public async Task GroupByTypeSignature_DifferentSourceTypes_SeparateGroups() { + const int ExpectedGroupCount = 2; var inv1 = ModelFactory.CreateInvocationInfo( sourceTypeFullName: "global::TestApp.ViewModelA", isBeforeChange: true); @@ -54,84 +56,77 @@ public async Task GroupByTypeSignature_DifferentSourceTypes_SeparateGroups() var groups = ObservationCodeGenerator.GroupByTypeSignature(invocations); - await Assert.That(groups.Count).IsEqualTo(2); + await Assert.That(groups.Count).IsEqualTo(ExpectedGroupCount); } - /// - /// Verifies GenerateConcreteOverload dispatches to CallerArgExpr when supported. - /// + /// Verifies GenerateConcreteOverload dispatches to CallerArgExpr when supported. /// A task representing the asynchronous test operation. [Test] public async Task GenerateConcreteOverload_CallerArgExprSupported_GeneratesCallerArgExprOverload() { var sb = new StringBuilder(); - var inv = ModelFactory.CreateInvocationInfo(isBeforeChange: true, methodName: "WhenChanging"); + var inv = ModelFactory.CreateInvocationInfo(isBeforeChange: true, methodName: WhenChangingName); var group = new ObservationCodeGenerator.TypeGroup(inv, [inv]); - ObservationCodeGenerator.GenerateConcreteOverload(sb, group, true, "WhenChanging"); + ObservationCodeGenerator.GenerateConcreteOverload(sb, group, true, WhenChangingName); var result = sb.ToString(); await Assert.That(result).Contains("CallerArgumentExpression"); - await Assert.That(result).Contains("__WhenChanging_"); + await Assert.That(result).Contains(WhenChangingLocal); } - /// - /// Verifies GenerateConcreteOverload dispatches to CallerFilePath when not supported. - /// + /// Verifies GenerateConcreteOverload dispatches to CallerFilePath when not supported. /// A task representing the asynchronous test operation. [Test] public async Task GenerateConcreteOverload_CallerArgExprNotSupported_GeneratesCallerFilePathOverload() { var sb = new StringBuilder(); - var inv = ModelFactory.CreateInvocationInfo(isBeforeChange: true, methodName: "WhenChanging"); + var inv = ModelFactory.CreateInvocationInfo(isBeforeChange: true, methodName: WhenChangingName); var group = new ObservationCodeGenerator.TypeGroup(inv, [inv]); - ObservationCodeGenerator.GenerateConcreteOverload(sb, group, false, "WhenChanging"); + ObservationCodeGenerator.GenerateConcreteOverload(sb, group, false, WhenChangingName); var result = sb.ToString(); await Assert.That(result).Contains("CallerFilePath"); await Assert.That(result).Contains("callerLineNumber"); } - /// - /// Verifies GenerateConcreteOverload with CallerArgExpr generates propertyExpression dispatch for WhenChanging. - /// + /// Verifies GenerateConcreteOverload with CallerArgExpr generates propertyExpression dispatch for WhenChanging. /// A task representing the asynchronous test operation. [Test] public async Task GenerateConcreteOverload_CallerArgExpr_GeneratesPropertyExpressionDispatch() { var sb = new StringBuilder(); - var inv = ModelFactory.CreateInvocationInfo(isBeforeChange: true, methodName: "WhenChanging"); + var inv = ModelFactory.CreateInvocationInfo(isBeforeChange: true, methodName: WhenChangingName); var group = new ObservationCodeGenerator.TypeGroup(inv, [inv]); - ObservationCodeGenerator.GenerateConcreteOverload(sb, group, true, "WhenChanging"); + ObservationCodeGenerator.GenerateConcreteOverload(sb, group, true, WhenChangingName); var result = sb.ToString(); await Assert.That(result).Contains("Expression =="); - await Assert.That(result).Contains("WhenChanging"); - await Assert.That(result).Contains("__WhenChanging_"); + await Assert.That(result).Contains(WhenChangingName); + await Assert.That(result).Contains(WhenChangingLocal); } - /// - /// Verifies GenerateConcreteOverload with CallerFilePath generates file path + line number dispatch for WhenChanging. - /// + /// Verifies GenerateConcreteOverload with CallerFilePath generates file path + line number dispatch for WhenChanging. /// A task representing the asynchronous test operation. [Test] public async Task GenerateConcreteOverload_CallerFilePath_GeneratesFilePathDispatch() { + const int CallerLineNumber = 42; var sb = new StringBuilder(); var inv = ModelFactory.CreateInvocationInfo( "/src/ViewModels/MyViewModel.cs", - 42, + CallerLineNumber, isBeforeChange: true, - methodName: "WhenChanging"); + methodName: WhenChangingName); var group = new ObservationCodeGenerator.TypeGroup(inv, [inv]); - ObservationCodeGenerator.GenerateConcreteOverload(sb, group, false, "WhenChanging"); + ObservationCodeGenerator.GenerateConcreteOverload(sb, group, false, WhenChangingName); var result = sb.ToString(); await Assert.That(result).Contains("callerLineNumber == 42"); await Assert.That(result).Contains("callerFilePath.EndsWith"); - await Assert.That(result).Contains("__WhenChanging_"); + await Assert.That(result).Contains(WhenChangingLocal); } } diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/ExtractorEdgeCaseTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/ExtractorEdgeCaseTests.cs index ac9120b..d7bcc78 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/ExtractorEdgeCaseTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/ExtractorEdgeCaseTests.cs @@ -13,6 +13,18 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests; /// public class ExtractorEdgeCaseTests { + /// The BindCommandDispatch.g.cs name these tests generate against. + private const string BindCommandDispatchgcsName = "BindCommandDispatch.g.cs"; + + /// The BindInteractionDispatch.g.cs name these tests generate against. + private const string BindInteractionDispatchgcsName = "BindInteractionDispatch.g.cs"; + + /// The BindOneWayDispatch.g.cs name these tests generate against. + private const string BindOneWayDispatchgcsName = "BindOneWayDispatch.g.cs"; + + /// The WhenAnyObservableDispatch.g.cs name these tests generate against. + private const string WhenAnyObservableDispatchgcsName = "WhenAnyObservableDispatch.g.cs"; + /// /// Verifies that a BindOneWay call on a custom (non-stub) extension class is skipped. /// Exercises the ContainingType name guard in BindingExtractor (line 41). @@ -59,7 +71,7 @@ public static void Execute(MyViewModel vm, MyView view) var result = TestHelper.RunGenerator(source); await result.HasNoGeneratorDiagnostics(); - await result.DoesNotHaveGeneratedSource("BindOneWayDispatch.g.cs"); + await result.DoesNotHaveGeneratedSource(BindOneWayDispatchgcsName); } /// @@ -109,7 +121,7 @@ public static void Execute(MyViewModel vm, MyView view) var result = TestHelper.RunGenerator(source); await result.HasNoGeneratorDiagnostics(); - await result.DoesNotHaveGeneratedSource("BindCommandDispatch.g.cs"); + await result.DoesNotHaveGeneratedSource(BindCommandDispatchgcsName); } /// @@ -151,7 +163,7 @@ public static void Execute(MyViewModel vm) var result = TestHelper.RunGenerator(source); await result.HasNoGeneratorDiagnostics(); - await result.DoesNotHaveGeneratedSource("WhenAnyObservableDispatch.g.cs"); + await result.DoesNotHaveGeneratedSource(WhenAnyObservableDispatchgcsName); } /// @@ -200,7 +212,7 @@ public static void Execute(MyViewModel vm, MyView view) var result = TestHelper.RunGenerator(source); await result.HasNoGeneratorDiagnostics(); - await result.DoesNotHaveGeneratedSource("BindInteractionDispatch.g.cs"); + await result.DoesNotHaveGeneratedSource(BindInteractionDispatchgcsName); } /// @@ -245,7 +257,7 @@ public static void Execute(MyViewModel vm, MyView view) var result = TestHelper.RunGenerator(source); await result.HasNoGeneratorDiagnostics(); - await result.DoesNotHaveGeneratedSource("BindOneWayDispatch.g.cs"); + await result.DoesNotHaveGeneratedSource(BindOneWayDispatchgcsName); } /// @@ -292,7 +304,7 @@ public static void Execute(MyViewModel vm, MyView view) var result = TestHelper.RunGenerator(source); await result.HasNoGeneratorDiagnostics(); - await result.DoesNotHaveGeneratedSource("BindCommandDispatch.g.cs"); + await result.DoesNotHaveGeneratedSource(BindCommandDispatchgcsName); } /// @@ -339,7 +351,7 @@ public static void Execute(MyViewModel vm, MyView view) var result = TestHelper.RunGenerator(source); await result.HasNoGeneratorDiagnostics(); - await result.DoesNotHaveGeneratedSource("BindCommandDispatch.g.cs"); + await result.DoesNotHaveGeneratedSource(BindCommandDispatchgcsName); } /// @@ -390,7 +402,7 @@ public static void Execute(MyViewModel vm, MyView view) var result = TestHelper.RunGenerator(source); await result.HasNoGeneratorDiagnostics(); - await result.DoesNotHaveGeneratedSource("BindInteractionDispatch.g.cs"); + await result.DoesNotHaveGeneratedSource(BindInteractionDispatchgcsName); } /// @@ -429,7 +441,7 @@ public static void Execute(MyViewModel vm) var result = TestHelper.RunGenerator(source); await result.HasNoGeneratorDiagnostics(); - await result.DoesNotHaveGeneratedSource("WhenAnyObservableDispatch.g.cs"); + await result.DoesNotHaveGeneratedSource(WhenAnyObservableDispatchgcsName); } /// @@ -507,7 +519,7 @@ public static void Execute() var result = TestHelper.RunGenerator(source); await result.HasNoGeneratorDiagnostics(); - await result.DoesNotHaveGeneratedSource("WhenAnyObservableDispatch.g.cs"); + await result.DoesNotHaveGeneratedSource(WhenAnyObservableDispatchgcsName); } /// @@ -533,7 +545,7 @@ public static void Execute() var result = TestHelper.RunGenerator(source); await result.HasNoGeneratorDiagnostics(); - await result.DoesNotHaveGeneratedSource("BindCommandDispatch.g.cs"); + await result.DoesNotHaveGeneratedSource(BindCommandDispatchgcsName); } /// @@ -559,7 +571,7 @@ public static void Execute() var result = TestHelper.RunGenerator(source); await result.HasNoGeneratorDiagnostics(); - await result.DoesNotHaveGeneratedSource("BindInteractionDispatch.g.cs"); + await result.DoesNotHaveGeneratedSource(BindInteractionDispatchgcsName); } /// @@ -585,7 +597,7 @@ public static void Execute() var result = TestHelper.RunGenerator(source); await result.HasNoGeneratorDiagnostics(); - await result.DoesNotHaveGeneratedSource("BindOneWayDispatch.g.cs"); + await result.DoesNotHaveGeneratedSource(BindOneWayDispatchgcsName); } /// @@ -638,7 +650,7 @@ public static void Execute(MyViewModel vm, MyView view) var result = TestHelper.RunGenerator(source); await result.HasNoGeneratorDiagnostics(); - await result.DoesNotHaveGeneratedSource("BindOneWayDispatch.g.cs"); + await result.DoesNotHaveGeneratedSource(BindOneWayDispatchgcsName); } /// @@ -691,7 +703,7 @@ public static void Execute(MyViewModel vm, MyView view) var result = TestHelper.RunGenerator(source); await result.HasNoGeneratorDiagnostics(); - await result.DoesNotHaveGeneratedSource("BindCommandDispatch.g.cs"); + await result.DoesNotHaveGeneratedSource(BindCommandDispatchgcsName); } /// @@ -744,7 +756,7 @@ public static void Execute(MyViewModel vm, MyView view) var result = TestHelper.RunGenerator(source); await result.HasNoGeneratorDiagnostics(); - await result.DoesNotHaveGeneratedSource("BindInteractionDispatch.g.cs"); + await result.DoesNotHaveGeneratedSource(BindInteractionDispatchgcsName); } /// diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/CollectibleAssemblyLoadContext.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/CollectibleAssemblyLoadContext.cs index 3a1662f..814de69 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/CollectibleAssemblyLoadContext.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/CollectibleAssemblyLoadContext.cs @@ -13,9 +13,7 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests.Helpers; /// public sealed class CollectibleAssemblyLoadContext : AssemblyLoadContext { - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. public CollectibleAssemblyLoadContext() : base(true) { diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/CommandExtractorHelperTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/CommandExtractorHelperTests.cs index 9df4e7b..31cc62c 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/CommandExtractorHelperTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/CommandExtractorHelperTests.cs @@ -7,70 +7,63 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests.Helpers; -/// -/// Tests for internal helper methods. -/// +/// Tests for internal helper methods. public class CommandExtractorHelperTests { - /// - /// Verifies that IsToEventArgument returns true for a named argument with "toEvent". - /// + /// Verifies that IsToEventArgument returns true for a named argument with "toEvent". /// A task representing the asynchronous test operation. [Test] public async Task IsToEventArgument_NamedToEvent_ReturnsTrue() { + const int SampleValue = 5; var argument = ParseFirstArgument("Method(toEvent: \"Click\")"); - var result = CommandExtractor.IsToEventArgument(argument, 0, 5); + var result = CommandExtractor.IsToEventArgument(argument, 0, SampleValue); await Assert.That(result).IsTrue(); } - /// - /// Verifies that IsToEventArgument returns false for a named argument with a different name. - /// + /// Verifies that IsToEventArgument returns false for a named argument with a different name. /// A task representing the asynchronous test operation. [Test] public async Task IsToEventArgument_NamedOtherParam_ReturnsFalse() { + const int SampleValue = 5; var argument = ParseFirstArgument("Method(scheduler: null)"); - var result = CommandExtractor.IsToEventArgument(argument, 0, 5); + var result = CommandExtractor.IsToEventArgument(argument, 0, SampleValue); await Assert.That(result).IsFalse(); } - /// - /// Verifies that IsToEventArgument returns true for a positional argument at the correct index. - /// + /// Verifies that IsToEventArgument returns true for a positional argument at the correct index. /// A task representing the asynchronous test operation. [Test] public async Task IsToEventArgument_PositionalAtCorrectIndex_ReturnsTrue() { + const int SampleValue = 3; var argument = ParseFirstArgument("Method(\"Click\")"); - var result = CommandExtractor.IsToEventArgument(argument, 3, 3); + var result = CommandExtractor.IsToEventArgument(argument, SampleValue, SampleValue); await Assert.That(result).IsTrue(); } - /// - /// Verifies that IsToEventArgument returns false for a positional argument at the wrong index. - /// + /// Verifies that IsToEventArgument returns false for a positional argument at the wrong index. /// A task representing the asynchronous test operation. [Test] public async Task IsToEventArgument_PositionalAtWrongIndex_ReturnsFalse() { + const int SampleValue = 2; + const int SampleValue2 = 5; var argument = ParseFirstArgument("Method(\"Click\")"); - var result = CommandExtractor.IsToEventArgument(argument, 2, 5); + var result = CommandExtractor.IsToEventArgument(argument, SampleValue, SampleValue2); await Assert.That(result).IsFalse(); } - /// - /// Verifies that HasCommandProperties returns false for a type with no Command property. - /// + /// Verifies that HasCommandProperties returns false for a type with no Command property. /// A task representing the asynchronous test operation. [Test] public async Task HasCommandProperties_NoCommand_ReturnsFalse() @@ -96,9 +89,7 @@ public class PlainControl await Assert.That(hasParam).IsFalse(); } - /// - /// Verifies that HasCommandProperties returns true for a type with a settable Command (ICommand) property. - /// + /// Verifies that HasCommandProperties returns true for a type with a settable Command (ICommand) property. /// A task representing the asynchronous test operation. [Test] public async Task HasCommandProperties_WithCommand_ReturnsTrue() @@ -125,9 +116,7 @@ public class ButtonControl await Assert.That(hasParam).IsFalse(); } - /// - /// Verifies that HasCommandProperties returns true with CommandParameter when both exist. - /// + /// Verifies that HasCommandProperties returns true with CommandParameter when both exist. /// A task representing the asynchronous test operation. [Test] public async Task HasCommandProperties_WithCommandAndParameter_ReturnsTrueWithParam() @@ -155,9 +144,7 @@ public class ButtonControl await Assert.That(hasParam).IsTrue(); } - /// - /// Verifies that HasCommandProperties does not match a readonly Command property. - /// + /// Verifies that HasCommandProperties does not match a readonly Command property. /// A task representing the asynchronous test operation. [Test] public async Task HasCommandProperties_ReadOnlyCommand_ReturnsFalse() @@ -184,9 +171,7 @@ public class ReadOnlyCommandControl await Assert.That(hasParam).IsFalse(); } - /// - /// Verifies that HasEnabledProperty returns false when no Enabled property exists. - /// + /// Verifies that HasEnabledProperty returns false when no Enabled property exists. /// A task representing the asynchronous test operation. [Test] public async Task HasEnabledProperty_NoEnabledProperty_ReturnsFalse() @@ -211,9 +196,7 @@ public class PlainControl await Assert.That(result).IsFalse(); } - /// - /// Verifies that HasEnabledProperty returns true when a settable bool Enabled property exists. - /// + /// Verifies that HasEnabledProperty returns true when a settable bool Enabled property exists. /// A task representing the asynchronous test operation. [Test] public async Task HasEnabledProperty_WithEnabled_ReturnsTrue() @@ -238,9 +221,7 @@ public class WinFormsControl await Assert.That(result).IsTrue(); } - /// - /// Verifies that HasEnabledProperty returns false for non-bool Enabled property. - /// + /// Verifies that HasEnabledProperty returns false for non-bool Enabled property. /// A task representing the asynchronous test operation. [Test] public async Task HasEnabledProperty_StringEnabled_ReturnsFalse() @@ -306,10 +287,7 @@ public void Method(Vm vm, View view, string s) { } await Assert.That(result).IsNull(); } - /// - /// Verifies that FindParameterLambda returns null when args after index 3 - /// are not valid lambda expressions. - /// + /// Verifies that FindParameterLambda returns null when args after index 3 are not valid lambda expressions. /// A task representing the asynchronous test operation. [Test] public async Task FindParameterLambda_NonLambdaArgs_ReturnsNull() @@ -347,9 +325,7 @@ public void Method(Vm vm, View view, string s1, string s2) { } await Assert.That(result).IsNull(); } - /// - /// Parses an invocation expression and returns the first argument. - /// + /// Parses an invocation expression and returns the first argument. /// The invocation expression text to parse. /// The first argument syntax node. private static Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentSyntax ParseFirstArgument(string expression) @@ -359,9 +335,7 @@ private static Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentSyntax ParseFirstArg return invocation.ArgumentList.Arguments[0]; } - /// - /// Gets the first class symbol from a syntax tree. - /// + /// Gets the first class symbol from a syntax tree. /// The syntax tree. /// The semantic model. /// The first named type symbol. diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/EventHelpersTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/EventHelpersTests.cs index 10d0bd4..5b51898 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/EventHelpersTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/EventHelpersTests.cs @@ -10,11 +10,15 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests; -/// -/// Tests for methods. -/// +/// Tests for methods. public class EventHelpersTests { + /// The Click name these tests generate against. + private const string ClickName = "Click"; + + /// The MyButton name these tests generate against. + private const string MyButtonName = "MyButton"; + /// /// Verifies FindEventArgsType returns "global::System.EventArgs" when the event's delegate /// type has a non-standard number of parameters (e.g. Action with 0 params). @@ -32,16 +36,14 @@ public class MyButton { public event Action Clicked; } """; var compilation = TestHelper.CreateCompilation(source, LanguageVersion.CSharp10); - var typeSymbol = GetNamedTypeSymbol(compilation, "MyButton"); + var typeSymbol = GetNamedTypeSymbol(compilation, MyButtonName); var result = EventHelpers.FindEventArgsType(typeSymbol, "Clicked"); await Assert.That(result).IsEqualTo("global::System.EventArgs"); } - /// - /// Verifies FindEventArgsType returns null when the type has no matching event. - /// + /// Verifies FindEventArgsType returns null when the type has no matching event. /// A task representing the asynchronous test operation. [Test] public async Task FindEventArgsType_NoMatchingEvent_ReturnsNull() @@ -54,16 +56,14 @@ public class MyButton { } """; var compilation = TestHelper.CreateCompilation(source); - var typeSymbol = GetNamedTypeSymbol(compilation, "MyButton"); + var typeSymbol = GetNamedTypeSymbol(compilation, MyButtonName); - var result = EventHelpers.FindEventArgsType(typeSymbol, "Click"); + var result = EventHelpers.FindEventArgsType(typeSymbol, ClickName); await Assert.That(result).IsNull(); } - /// - /// Verifies FindDefaultEvent returns the first matching default event name. - /// + /// Verifies FindDefaultEvent returns the first matching default event name. /// A task representing the asynchronous test operation. [Test] public async Task FindDefaultEvent_ControlWithClickEvent_ReturnsClick() @@ -77,17 +77,15 @@ public class MyButton { public event EventHandler Click; } """; var compilation = TestHelper.CreateCompilation(source, LanguageVersion.CSharp10); - var typeSymbol = GetNamedTypeSymbol(compilation, "MyButton"); + var typeSymbol = GetNamedTypeSymbol(compilation, MyButtonName); var eventName = EventHelpers.FindDefaultEvent(typeSymbol, out var argsType); - await Assert.That(eventName).IsEqualTo("Click"); + await Assert.That(eventName).IsEqualTo(ClickName); await Assert.That(argsType).IsNotNull(); } - /// - /// Verifies FindDefaultEvent returns TouchUpInside for controls with that event. - /// + /// Verifies FindDefaultEvent returns TouchUpInside for controls with that event. /// A task representing the asynchronous test operation. [Test] public async Task FindDefaultEvent_ControlWithTouchUpInsideEvent_ReturnsTouchUpInside() @@ -108,9 +106,7 @@ public class TouchControl { public event EventHandler TouchUpInside; } await Assert.That(eventName).IsEqualTo("TouchUpInside"); } - /// - /// Verifies FindDefaultEvent returns null when no default event matches. - /// + /// Verifies FindDefaultEvent returns null when no default event matches. /// A task representing the asynchronous test operation. [Test] public async Task FindDefaultEvent_ControlWithNoMatchingEvent_ReturnsNull() @@ -154,7 +150,7 @@ public class ControlWithClickProperty var compilation = TestHelper.CreateCompilation(source); var typeSymbol = GetNamedTypeSymbol(compilation, "ControlWithClickProperty"); - var result = EventHelpers.FindEventArgsType(typeSymbol, "Click"); + var result = EventHelpers.FindEventArgsType(typeSymbol, ClickName); await Assert.That(result).IsNull(); } @@ -180,14 +176,12 @@ public void Click() { } var compilation = TestHelper.CreateCompilation(source); var typeSymbol = GetNamedTypeSymbol(compilation, "ControlWithClickMethod"); - var result = EventHelpers.FindEventArgsType(typeSymbol, "Click"); + var result = EventHelpers.FindEventArgsType(typeSymbol, ClickName); await Assert.That(result).IsNull(); } - /// - /// Gets a named type symbol from a compilation. - /// + /// Gets a named type symbol from a compilation. /// The compilation. /// The type name. /// The named type symbol. diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/ExtractorValidationTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/ExtractorValidationTests.cs index 8b76881..5980536 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/ExtractorValidationTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/ExtractorValidationTests.cs @@ -9,37 +9,34 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests.Helpers; -/// -/// Unit tests for helper methods. -/// Tests the guard-clause branches extracted from extractor classes. -/// +/// Unit tests for helper methods. Tests the guard-clause branches extracted from extractor classes. public class ExtractorValidationTests { - /// - /// Verifies that the stub extension class name is recognized. - /// + /// The selector name these tests generate against. + private const string SelectorName = "selector"; + + /// The string name these tests generate against. + private const string StringName = "string"; + + /// Verifies that the stub extension class name is recognized. /// A task representing the asynchronous test operation. [Test] public async Task IsRecognizedExtensionClass_StubClassName_ReturnsTrue() { - var result = ExtractorValidation.IsRecognizedExtensionClass("ReactiveUIBindingExtensions"); + var result = ExtractorValidation.IsRecognizedExtensionClass(nameof(ReactiveUIBindingExtensions)); await Assert.That(result).IsTrue(); } - /// - /// Verifies that the scheduler extension class name is recognized. - /// + /// Verifies that the scheduler extension class name is recognized. /// A task representing the asynchronous test operation. [Test] public async Task IsRecognizedExtensionClass_SchedulerClassName_ReturnsTrue() { - var result = ExtractorValidation.IsRecognizedExtensionClass("ReactiveSchedulerExtensions"); + var result = ExtractorValidation.IsRecognizedExtensionClass(nameof(ReactiveSchedulerExtensions)); await Assert.That(result).IsTrue(); } - /// - /// Verifies that the generated extension class name is recognized. - /// + /// Verifies that the generated extension class name is recognized. /// A task representing the asynchronous test operation. [Test] public async Task IsRecognizedExtensionClass_GeneratedClassName_ReturnsTrue() @@ -48,9 +45,7 @@ public async Task IsRecognizedExtensionClass_GeneratedClassName_ReturnsTrue() await Assert.That(result).IsTrue(); } - /// - /// Verifies that an unrecognized class name is rejected. - /// + /// Verifies that an unrecognized class name is rejected. /// A task representing the asynchronous test operation. [Test] public async Task IsRecognizedExtensionClass_UnknownClassName_ReturnsFalse() @@ -59,9 +54,7 @@ public async Task IsRecognizedExtensionClass_UnknownClassName_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies that null is rejected as unrecognized. - /// + /// Verifies that null is rejected as unrecognized. /// A task representing the asynchronous test operation. [Test] public async Task IsRecognizedExtensionClass_Null_ReturnsFalse() @@ -70,9 +63,7 @@ public async Task IsRecognizedExtensionClass_Null_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies that an empty string is rejected as unrecognized. - /// + /// Verifies that an empty string is rejected as unrecognized. /// A task representing the asynchronous test operation. [Test] public async Task IsRecognizedExtensionClass_Empty_ReturnsFalse() @@ -81,53 +72,49 @@ public async Task IsRecognizedExtensionClass_Empty_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies that argument count at the minimum is accepted. - /// + /// Verifies that argument count at the minimum is accepted. /// A task representing the asynchronous test operation. [Test] public async Task HasMinimumArguments_ExactMinimum_ReturnsTrue() { - var result = ExtractorValidation.HasMinimumArguments(3, 3); + const int ArgumentCount = 3; + var result = ExtractorValidation.HasMinimumArguments(ArgumentCount, ArgumentCount); await Assert.That(result).IsTrue(); } - /// - /// Verifies that argument count above the minimum is accepted. - /// + /// Verifies that argument count above the minimum is accepted. /// A task representing the asynchronous test operation. [Test] public async Task HasMinimumArguments_AboveMinimum_ReturnsTrue() { - var result = ExtractorValidation.HasMinimumArguments(5, 3); + const int ArgumentCount = 5; + const int MinimumRequired = 3; + var result = ExtractorValidation.HasMinimumArguments(ArgumentCount, MinimumRequired); await Assert.That(result).IsTrue(); } - /// - /// Verifies that argument count below the minimum is rejected. - /// + /// Verifies that argument count below the minimum is rejected. /// A task representing the asynchronous test operation. [Test] public async Task HasMinimumArguments_BelowMinimum_ReturnsFalse() { - var result = ExtractorValidation.HasMinimumArguments(2, 3); + const int ArgumentCount = 2; + const int MinimumRequired = 3; + var result = ExtractorValidation.HasMinimumArguments(ArgumentCount, MinimumRequired); await Assert.That(result).IsFalse(); } - /// - /// Verifies that zero arguments is rejected when minimum is required. - /// + /// Verifies that zero arguments is rejected when minimum is required. /// A task representing the asynchronous test operation. [Test] public async Task HasMinimumArguments_Zero_ReturnsFalse() { - var result = ExtractorValidation.HasMinimumArguments(0, 3); + const int MinimumRequired = 3; + var result = ExtractorValidation.HasMinimumArguments(0, MinimumRequired); await Assert.That(result).IsFalse(); } - /// - /// Verifies that a populated immutable array is accepted. - /// + /// Verifies that a populated immutable array is accepted. /// A task representing the asynchronous test operation. [Test] public async Task HasItems_PopulatedArray_ReturnsTrue() @@ -137,9 +124,7 @@ public async Task HasItems_PopulatedArray_ReturnsTrue() await Assert.That(result).IsTrue(); } - /// - /// Verifies that a single-item array is accepted. - /// + /// Verifies that a single-item array is accepted. /// A task representing the asynchronous test operation. [Test] public async Task HasItems_SingleItem_ReturnsTrue() @@ -149,9 +134,7 @@ public async Task HasItems_SingleItem_ReturnsTrue() await Assert.That(result).IsTrue(); } - /// - /// Verifies that an empty immutable array is rejected. - /// + /// Verifies that an empty immutable array is rejected. /// A task representing the asynchronous test operation. [Test] public async Task HasItems_EmptyArray_ReturnsFalse() @@ -161,9 +144,7 @@ public async Task HasItems_EmptyArray_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies that a default (uninitialized) immutable array is rejected. - /// + /// Verifies that a default (uninitialized) immutable array is rejected. /// A task representing the asynchronous test operation. [Test] public async Task HasItems_DefaultArray_ReturnsFalse() @@ -209,109 +190,99 @@ public async Task ResolveEventArgsType_NullDelegateType_ReturnsFallback() await Assert.That(result).IsEqualTo("global::System.EventArgs"); } - /// - /// Verifies that FindSelectorReturnType returns null when the parameters array is empty. - /// + /// Verifies that FindSelectorReturnType returns null when the parameters array is empty. /// A task representing the asynchronous test operation. [Test] public async Task FindSelectorReturnType_EmptyParameters_ReturnsNull() { var result = ExtractorValidation.FindSelectorReturnType( [], - "selector"); + SelectorName); await Assert.That(result).IsNull(); } - /// - /// Verifies that FindSelectorReturnType returns null when no parameter matches the name. - /// + /// Verifies that FindSelectorReturnType returns null when no parameter matches the name. /// A task representing the asynchronous test operation. [Test] public async Task FindSelectorReturnType_NoMatchingParameter_ReturnsNull() { var typeArg = Substitute.For(); - typeArg.ToDisplayString(Arg.Any()).Returns("string"); + _ = typeArg.ToDisplayString(Arg.Any()).Returns(StringName); var funcType = Substitute.For(); - funcType.TypeArguments.Returns([typeArg]); + _ = funcType.TypeArguments.Returns([typeArg]); var param = Substitute.For(); - param.Name.Returns("otherParam"); - param.Type.Returns(funcType); + _ = param.Name.Returns("otherParam"); + _ = param.Type.Returns(funcType); var parameters = ImmutableArray.Create(param); - var result = ExtractorValidation.FindSelectorReturnType(parameters, "selector"); + var result = ExtractorValidation.FindSelectorReturnType(parameters, SelectorName); await Assert.That(result).IsNull(); } - /// - /// Verifies that FindSelectorReturnType returns the return type when a matching parameter is found. - /// + /// Verifies that FindSelectorReturnType returns the return type when a matching parameter is found. /// A task representing the asynchronous test operation. [Test] public async Task FindSelectorReturnType_MatchingParameter_ReturnsType() { var typeArg = Substitute.For(); - typeArg.ToDisplayString(Arg.Any()).Returns("string"); + _ = typeArg.ToDisplayString(Arg.Any()).Returns(StringName); var funcType = Substitute.For(); - funcType.TypeArguments.Returns([typeArg]); + _ = funcType.TypeArguments.Returns([typeArg]); var param = Substitute.For(); - param.Name.Returns("selector"); - param.Type.Returns(funcType); + _ = param.Name.Returns(SelectorName); + _ = param.Type.Returns(funcType); var parameters = ImmutableArray.Create(param); - var result = ExtractorValidation.FindSelectorReturnType(parameters, "selector"); + var result = ExtractorValidation.FindSelectorReturnType(parameters, SelectorName); - await Assert.That(result).IsEqualTo("string"); + await Assert.That(result).IsEqualTo(StringName); } - /// - /// Verifies that FindSelectorReturnType matches any of multiple parameter names. - /// + /// Verifies that FindSelectorReturnType matches any of multiple parameter names. /// A task representing the asynchronous test operation. [Test] public async Task FindSelectorReturnType_MultipleNames_MatchesSecondName() { var typeArg = Substitute.For(); - typeArg.ToDisplayString(Arg.Any()).Returns("int"); + _ = typeArg.ToDisplayString(Arg.Any()).Returns("int"); var funcType = Substitute.For(); - funcType.TypeArguments.Returns([typeArg]); + _ = funcType.TypeArguments.Returns([typeArg]); var param = Substitute.For(); - param.Name.Returns("conversionFunc"); - param.Type.Returns(funcType); + _ = param.Name.Returns("conversionFunc"); + _ = param.Type.Returns(funcType); var parameters = ImmutableArray.Create(param); - var result = ExtractorValidation.FindSelectorReturnType(parameters, "selector", "conversionFunc"); + var result = ExtractorValidation.FindSelectorReturnType(parameters, SelectorName, "conversionFunc"); await Assert.That(result).IsEqualTo("int"); } - /// - /// Verifies that FindSelectorReturnType skips parameters with non-generic types. - /// + /// Verifies that FindSelectorReturnType skips parameters with non-generic types. /// A task representing the asynchronous test operation. [Test] public async Task FindSelectorReturnType_NonGenericType_ReturnsNull() { var nonGenericType = Substitute.For(); - nonGenericType.TypeArguments.Returns([]); + _ = nonGenericType.TypeArguments.Returns([]); var param = Substitute.For(); - param.Name.Returns("selector"); - param.Type.Returns(nonGenericType); + _ = param.Name.Returns(SelectorName); + _ = param.Type.Returns(nonGenericType); var parameters = ImmutableArray.Create(param); - var result = ExtractorValidation.FindSelectorReturnType(parameters, "selector"); + var result = ExtractorValidation.FindSelectorReturnType(parameters, SelectorName); await Assert.That(result).IsNull(); } diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/GeneratedCodeAssertionMixins.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/GeneratedCodeAssertionMixins.cs new file mode 100644 index 0000000..7950741 --- /dev/null +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/GeneratedCodeAssertionMixins.cs @@ -0,0 +1,76 @@ +// Copyright (c) 2019-2026 ReactiveUI Association Incorporated. All rights reserved. +// ReactiveUI Association Incorporated licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +namespace ReactiveUI.Binding.SourceGenerators.Tests.Helpers; + +/// TUnit assertion extension methods for . +internal static class GeneratedCodeAssertionMixins +{ + /// Provides the generator-output assertions for . + /// The generator test result being asserted about. + extension(GeneratorTestResult result) + { + /// Asserts that the output compilation has no errors. + /// A task representing the asynchronous assertion. + internal async Task CompilationSucceeds() + { + if (result.CompilationErrors.IsEmpty) + { + return; + } + + var errorMessages = string.Join( + Environment.NewLine, + result.CompilationErrors.Select(static d => $" {d.Id}: {d.GetMessage()} at {d.Location}")); + + await Assert.That(result.CompilationErrors.Length).IsEqualTo(0) + .Because( + $"Compilation should succeed but had {result.CompilationErrors.Length} error(s):{Environment.NewLine}{errorMessages}"); + } + + /// Asserts that a generated source file with the specified hint name exists. + /// The hint name of the generated file. + /// A task representing the asynchronous assertion. + internal async Task HasGeneratedSource(string hintName) => + await Assert.That(result.GeneratedSources.ContainsKey(hintName)).IsTrue() + .Because( + $"Expected generated source '{hintName}' but found: [{string.Join(", ", result.GeneratedSources.Keys)}]"); + + /// Asserts that a generated source file contains the specified text. + /// The hint name of the generated file. + /// The text expected in the generated source. + /// A task representing the asynchronous assertion. + internal async Task GeneratedSourceContains(string hintName, string text) + { + await result.HasGeneratedSource(hintName); + var source = result.GeneratedSources[hintName]; + await Assert.That(source).Contains(text); + } + + /// Asserts that no generated source file with the specified hint name exists. + /// The hint name that should NOT be present. + /// A task representing the asynchronous assertion. + internal async Task DoesNotHaveGeneratedSource(string hintName) => + await Assert.That(result.GeneratedSources.ContainsKey(hintName)).IsFalse() + .Because( + $"Expected no generated source '{hintName}' but found it among: [{string.Join(", ", result.GeneratedSources.Keys)}]"); + + /// Asserts that the generator produced no diagnostics. + /// A task representing the asynchronous assertion. + internal async Task HasNoGeneratorDiagnostics() + { + if (result.GeneratorDiagnostics.IsEmpty) + { + return; + } + + var diagnosticMessages = string.Join( + Environment.NewLine, + result.GeneratorDiagnostics.Select(static d => $" {d.Id}: {d.GetMessage()}")); + + await Assert.That(result.GeneratorDiagnostics.Length).IsEqualTo(0) + .Because($"Generator should produce no diagnostics but had:{Environment.NewLine}{diagnosticMessages}"); + } + } +} diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/GeneratedCodeAssertions.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/GeneratedCodeAssertions.cs deleted file mode 100644 index 7c1ea13..0000000 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/GeneratedCodeAssertions.cs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2019-2026 ReactiveUI Association Incorporated. All rights reserved. -// ReactiveUI Association Incorporated licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -namespace ReactiveUI.Binding.SourceGenerators.Tests.Helpers; - -/// -/// TUnit assertion extension methods for . -/// -internal static class GeneratedCodeAssertions -{ - /// - /// Asserts that the output compilation has no errors. - /// - /// The generator test result. - /// A task representing the asynchronous assertion. - public static async Task CompilationSucceeds(this GeneratorTestResult result) - { - if (result.CompilationErrors.Length == 0) - { - return; - } - - var errorMessages = string.Join( - Environment.NewLine, - result.CompilationErrors.Select(d => $" {d.Id}: {d.GetMessage()} at {d.Location}")); - - await Assert.That(result.CompilationErrors.Length).IsEqualTo(0) - .Because( - $"Compilation should succeed but had {result.CompilationErrors.Length} error(s):{Environment.NewLine}{errorMessages}"); - } - - /// - /// Asserts that a generated source file with the specified hint name exists. - /// - /// The generator test result. - /// The hint name of the generated file. - /// A task representing the asynchronous assertion. - public static async Task HasGeneratedSource(this GeneratorTestResult result, string hintName) => - await Assert.That(result.GeneratedSources.ContainsKey(hintName)).IsTrue() - .Because( - $"Expected generated source '{hintName}' but found: [{string.Join(", ", result.GeneratedSources.Keys)}]"); - - /// - /// Asserts that a generated source file contains the specified text. - /// - /// The generator test result. - /// The hint name of the generated file. - /// The text expected in the generated source. - /// A task representing the asynchronous assertion. - public static async Task GeneratedSourceContains(this GeneratorTestResult result, string hintName, string text) - { - await result.HasGeneratedSource(hintName); - var source = result.GeneratedSources[hintName]; - await Assert.That(source).Contains(text); - } - - /// - /// Asserts that no generated source file with the specified hint name exists. - /// - /// The generator test result. - /// The hint name that should NOT be present. - /// A task representing the asynchronous assertion. - public static async Task DoesNotHaveGeneratedSource(this GeneratorTestResult result, string hintName) => - await Assert.That(result.GeneratedSources.ContainsKey(hintName)).IsFalse() - .Because( - $"Expected no generated source '{hintName}' but found it among: [{string.Join(", ", result.GeneratedSources.Keys)}]"); - - /// - /// Asserts that the generator produced no diagnostics. - /// - /// The generator test result. - /// A task representing the asynchronous assertion. - public static async Task HasNoGeneratorDiagnostics(this GeneratorTestResult result) - { - if (result.GeneratorDiagnostics.Length == 0) - { - return; - } - - var diagnosticMessages = string.Join( - Environment.NewLine, - result.GeneratorDiagnostics.Select(d => $" {d.Id}: {d.GetMessage()}")); - - await Assert.That(result.GeneratorDiagnostics.Length).IsEqualTo(0) - .Because($"Generator should produce no diagnostics but had:{Environment.NewLine}{diagnosticMessages}"); - } -} diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/GeneratorTestResult.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/GeneratorTestResult.cs index 8c2e629..67566db 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/GeneratorTestResult.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/GeneratorTestResult.cs @@ -7,14 +7,10 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests.Helpers; -/// -/// Wraps the results of a source generator execution for assertion and verification. -/// +/// Wraps the results of a source generator execution for assertion and verification. public sealed class GeneratorTestResult { - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The generator driver after execution. /// The compilation after generator execution. /// Diagnostics produced by the generator itself. @@ -34,12 +30,12 @@ public GeneratorTestResult( CompilationErrors = [ ..compilationDiagnostics - .Where(d => d.Severity == DiagnosticSeverity.Error) + .Where(static d => d.Severity == DiagnosticSeverity.Error) ]; CompilationWarnings = [ ..compilationDiagnostics - .Where(d => d.Severity == DiagnosticSeverity.Warning) + .Where(static d => d.Severity == DiagnosticSeverity.Warning) ]; var generatedSources = new Dictionary(); @@ -55,38 +51,24 @@ public GeneratorTestResult( GeneratedSources = generatedSources; } - /// - /// Gets the generator driver after execution (for Verify snapshot testing). - /// + /// Gets the generator driver after execution (for Verify snapshot testing). public GeneratorDriver Driver { get; } - /// - /// Gets the compilation after generator execution. - /// + /// Gets the compilation after generator execution. public Compilation OutputCompilation { get; } - /// - /// Gets the diagnostics produced by the generator itself. - /// + /// Gets the diagnostics produced by the generator itself. public ImmutableArray GeneratorDiagnostics { get; } - /// - /// Gets the compilation diagnostics with severity Error. - /// + /// Gets the compilation diagnostics with severity Error. public ImmutableArray CompilationErrors { get; } - /// - /// Gets the compilation diagnostics with severity Warning. - /// + /// Gets the compilation diagnostics with severity Warning. public ImmutableArray CompilationWarnings { get; } - /// - /// Gets the generated source files as a dictionary of hint name to source text. - /// + /// Gets the generated source files as a dictionary of hint name to source text. public IReadOnlyDictionary GeneratedSources { get; } - /// - /// Gets a value indicating whether the output compilation has no errors. - /// - public bool CompilesWithoutErrors => CompilationErrors.Length == 0; + /// Gets a value indicating whether the output compilation has no errors. + public bool CompilesWithoutErrors => CompilationErrors.IsEmpty; } diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/ModelFactory.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/ModelFactory.cs index 6931f9d..31185f2 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/ModelFactory.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/ModelFactory.cs @@ -2,22 +2,21 @@ // ReactiveUI Association Incorporated licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System.Diagnostics.CodeAnalysis; using ReactiveUI.Binding.SourceGenerators.Models; namespace ReactiveUI.Binding.SourceGenerators.Tests.Helpers; -/// -/// Factory methods for creating test model POCOs with sensible defaults. -/// -[System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "Factory methods build value-equatable pipeline models with one optional parameter per model property; the count mirrors the models under test.")] +/// Factory methods for creating test model POCOs with sensible defaults. internal static class ModelFactory { - /// - /// Creates a with sensible defaults. - /// + /// The fully qualified name of the String type used by these tests. + private const string StringTypeName = "global::System.String"; + + /// The fully qualified name of the MyViewModel type used by these tests. + private const string MyViewModelTypeName = "global::TestApp.MyViewModel"; + + /// Creates a with sensible defaults. /// The property name. /// The fully qualified property type. /// The fully qualified declaring type. @@ -25,14 +24,12 @@ internal static class ModelFactory /// A new property path segment. internal static PropertyPathSegment CreatePropertyPathSegment( string name = "Name", - string type = "global::System.String", - string declaringType = "global::TestApp.MyViewModel", + string type = StringTypeName, + string declaringType = MyViewModelTypeName, bool isReferenceType = true) => new(name, type, declaringType, isReferenceType); - /// - /// Creates an with sensible defaults for a single-property WhenChanged invocation. - /// + /// Creates an with sensible defaults for a single-property WhenChanged invocation. /// The caller file path. /// The caller line number. /// The fully qualified source type. @@ -43,12 +40,13 @@ internal static PropertyPathSegment CreatePropertyPathSegment( /// The method name. /// The expression texts. If null, defaults based on property paths. /// A new invocation info. + [SuppressMessage("Design", "SST1472:Too many parameters", Justification = "parameter count is inherent to the model record this factory mirrors")] internal static InvocationInfo CreateInvocationInfo( string callerFilePath = "/src/ViewModels/MyViewModel.cs", int callerLineNumber = 42, - string sourceTypeFullName = "global::TestApp.MyViewModel", + string sourceTypeFullName = MyViewModelTypeName, EquatableArray>? propertyPaths = null, - string returnTypeFullName = "global::System.String", + string returnTypeFullName = StringTypeName, bool isBeforeChange = false, bool hasSelector = false, string methodName = "WhenChanged", @@ -73,9 +71,7 @@ internal static InvocationInfo CreateInvocationInfo( texts); } - /// - /// Creates a with sensible defaults. - /// + /// Creates a with sensible defaults. /// The caller file path. /// The caller line number. /// The fully qualified source type. @@ -92,15 +88,16 @@ internal static InvocationInfo CreateInvocationInfo( /// The target expression text. /// Whether a converter override is present. /// A new binding invocation info. + [SuppressMessage("Design", "SST1472:Too many parameters", Justification = "parameter count is inherent to the model record this factory mirrors")] internal static BindingInvocationInfo CreateBindingInvocationInfo( string callerFilePath = "/src/Views/MyView.cs", int callerLineNumber = 50, - string sourceTypeFullName = "global::TestApp.MyViewModel", + string sourceTypeFullName = MyViewModelTypeName, EquatableArray? sourcePropertyPath = null, string targetTypeFullName = "global::TestApp.MyView", EquatableArray? targetPropertyPath = null, - string sourcePropertyTypeFullName = "global::System.String", - string targetPropertyTypeFullName = "global::System.String", + string sourcePropertyTypeFullName = StringTypeName, + string targetPropertyTypeFullName = StringTypeName, bool hasConversion = false, bool hasScheduler = false, bool isTwoWay = false, @@ -110,9 +107,9 @@ internal static BindingInvocationInfo CreateBindingInvocationInfo( bool hasConverterOverride = false) { var sourcePath = sourcePropertyPath ?? new EquatableArray( - [CreatePropertyPathSegment("Name", "global::System.String", sourceTypeFullName)]); + [CreatePropertyPathSegment("Name", StringTypeName, sourceTypeFullName)]); var targetPath = targetPropertyPath ?? new EquatableArray( - [CreatePropertyPathSegment("Text", "global::System.String", targetTypeFullName)]); + [CreatePropertyPathSegment("Text", StringTypeName, targetTypeFullName)]); return new( callerFilePath, @@ -132,9 +129,7 @@ internal static BindingInvocationInfo CreateBindingInvocationInfo( hasConverterOverride); } - /// - /// Creates a with sensible defaults. - /// + /// Creates a with sensible defaults. /// The fully qualified type name. /// The metadata name. /// Whether IReactiveObject is implemented. @@ -147,8 +142,9 @@ internal static BindingInvocationInfo CreateBindingInvocationInfo( /// Whether Android View is inherited. /// The observable properties. If null, an empty array is created. /// A new class binding info. + [SuppressMessage("Design", "SST1472:Too many parameters", Justification = "parameter count is inherent to the model record this factory mirrors")] internal static ClassBindingInfo CreateClassBindingInfo( - string fullyQualifiedName = "global::TestApp.MyViewModel", + string fullyQualifiedName = MyViewModelTypeName, string metadataName = "MyViewModel", bool implementsIReactiveObject = false, bool implementsINPC = false, @@ -176,9 +172,7 @@ internal static ClassBindingInfo CreateClassBindingInfo( props); } - /// - /// Creates a with sensible defaults. - /// + /// Creates a with sensible defaults. /// The caller file path. /// The caller line number. /// The fully qualified view type. @@ -201,11 +195,12 @@ internal static ClassBindingInfo CreateClassBindingInfo( /// Whether the control has a CommandParameter property. /// Whether the control has an Enabled property. /// A new BindCommand invocation info. + [SuppressMessage("Design", "SST1472:Too many parameters", Justification = "parameter count is inherent to the model record this factory mirrors")] internal static BindCommandInvocationInfo CreateBindCommandInvocationInfo( string callerFilePath = "/src/Views/MyView.cs", int callerLineNumber = 50, string viewTypeFullName = "global::TestApp.MyView", - string viewModelTypeFullName = "global::TestApp.MyViewModel", + string viewModelTypeFullName = MyViewModelTypeName, EquatableArray? commandPropertyPath = null, EquatableArray? controlPropertyPath = null, string commandTypeFullName = "global::System.Windows.Input.ICommand", @@ -254,9 +249,7 @@ internal static BindCommandInvocationInfo CreateBindCommandInvocationInfo( hasEnabledProperty); } - /// - /// Creates an with sensible defaults. - /// + /// Creates an with sensible defaults. /// The property name. /// The fully qualified property type. /// Whether the property has a public getter. @@ -265,7 +258,7 @@ internal static BindCommandInvocationInfo CreateBindCommandInvocationInfo( /// A new observable property info. internal static ObservablePropertyInfo CreateObservablePropertyInfo( string propertyName = "Name", - string propertyTypeFullName = "global::System.String", + string propertyTypeFullName = StringTypeName, bool hasPublicGetter = true, bool isIndexer = false, bool isDependencyProperty = false) => diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/SharedSourceReader.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/SharedSourceReader.cs index d0688aa..ed41393 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/SharedSourceReader.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/SharedSourceReader.cs @@ -20,7 +20,7 @@ internal static partial class SharedSourceReader /// /// The path relative to the SharedScenarios root (e.g. "WhenChanged/SinglePropertyINPC"). /// A single merged source text containing all types from the scenario. - public static string ReadScenario(string scenarioPath) + internal static string ReadScenario(string scenarioPath) { var dir = Path.Combine(FindRoot(), scenarioPath); var files = Directory.GetFiles(dir, "*.cs"); @@ -42,10 +42,10 @@ public static string ReadScenario(string scenarioPath) // Copyright header foreach (var line in copyrightLines) { - sb.AppendLine(line); + _ = sb.AppendLine(line); } - sb.AppendLine(); + _ = sb.AppendLine(); // Deduplicated using directives (preserve blank line separators between groups) var usingList = usingDirectives.ToList(); @@ -53,46 +53,42 @@ public static string ReadScenario(string scenarioPath) foreach (var u in usingList) { var currentPrefix = ExtractUsingPrefix(u); - if (prevPrefix != null && currentPrefix != prevPrefix) + if (prevPrefix is not null && currentPrefix != prevPrefix) { - sb.AppendLine(); + _ = sb.AppendLine(); } - sb.AppendLine(u); + _ = sb.AppendLine(u); prevPrefix = currentPrefix; } - sb.AppendLine(); + _ = sb.AppendLine(); // Single namespace block with all type blocks - sb.AppendLine($"namespace {namespaceName}"); - sb.AppendLine("{"); + _ = sb.AppendLine($"namespace {namespaceName}"); + _ = sb.AppendLine("{"); for (var i = 0; i < typeBlocks.Count; i++) { if (i > 0) { - sb.AppendLine(); + _ = sb.AppendLine(); } - sb.AppendLine(typeBlocks[i]); + _ = sb.AppendLine(typeBlocks[i]); } - sb.AppendLine("}"); + _ = sb.AppendLine("}"); return sb.ToString(); } - /// - /// Finds the root directory of the SharedScenarios. - /// + /// Finds the root directory of the SharedScenarios. /// The path to the SharedScenarios directory. - internal static string FindRoot() - => Path.Combine(Path.GetDirectoryName(typeof(SharedSourceReader).Assembly.Location)!, "SharedScenarios"); + internal static string FindRoot() => + Path.Combine(Path.GetDirectoryName(typeof(SharedSourceReader).Assembly.Location)!, "SharedScenarios"); - /// - /// Parses a source file's lines to extract copyright headers, usings, and type blocks. - /// + /// Parses a source file's lines to extract copyright headers, usings, and type blocks. /// The lines of the file to parse. /// The list to which copyright lines will be added. /// The set to which using directives will be added. @@ -123,7 +119,7 @@ private static void ParseFile( body = ExtractTypeBlock(lines, ref i); } - if (body == null) + if (body is null) { return; } @@ -131,16 +127,14 @@ private static void ParseFile( typeBlocks.Add(body); } - /// - /// Collects up to the first three copyright comment lines from the file header. - /// + /// Collects up to the first three copyright comment lines from the file header. /// The file lines. /// The current line index, advanced past the header. /// The list to which copyright lines are added. private static void CollectCopyright(string[] lines, ref int i, List copyrightLines) { - while (i < lines.Length && - (lines[i].StartsWith("//", StringComparison.Ordinal) || string.IsNullOrWhiteSpace(lines[i]))) + while (i < lines.Length + && (lines[i].StartsWith("//", StringComparison.Ordinal) || string.IsNullOrWhiteSpace(lines[i]))) { if (copyrightLines.Count < 3 && lines[i].StartsWith("//", StringComparison.Ordinal)) { @@ -151,9 +145,7 @@ private static void CollectCopyright(string[] lines, ref int i, List cop } } - /// - /// Collects using directives, skipping blank lines, until a non-using, non-blank line is reached. - /// + /// Collects using directives, skipping blank lines, until a non-using, non-blank line is reached. /// The file lines. /// The current line index, advanced past the using block. /// The set to which using directives are added. @@ -178,9 +170,7 @@ private static void CollectUsings(string[] lines, ref int i, LinkedHashSet - /// Reads the namespace declaration if present, capturing the name on first encounter. - /// + /// Reads the namespace declaration if present, capturing the name on first encounter. /// The file lines. /// The current line index, advanced past the namespace line when matched. /// A reference to the shared namespace name. @@ -192,14 +182,14 @@ private static bool ReadNamespace(string[] lines, ref int i, ref string? namespa return false; } - var nsMatch = NamespaceRegex().Match(lines[i]); - if (!nsMatch.Success) + var namespaceMatch = NamespaceRegex().Match(lines[i]); + if (!namespaceMatch.Success) { return false; } - namespaceName ??= nsMatch.Groups[1].Value; - var isFileScoped = lines[i].TrimEnd().EndsWith(";", StringComparison.Ordinal); + namespaceName ??= namespaceMatch.Groups[1].Value; + var isFileScoped = lines[i].TrimEnd().EndsWith(';'); i++; return isFileScoped; } @@ -227,17 +217,10 @@ private static bool ReadNamespace(string[] lines, ref int i, ref string? namespa bodyEnd--; } - if (bodyStart > bodyEnd) - { - return null; - } - - return string.Join(Environment.NewLine, lines[bodyStart..(bodyEnd + 1)]); + return bodyStart > bodyEnd ? null : string.Join(Environment.NewLine, lines[bodyStart..(bodyEnd + 1)]); } - /// - /// Advances past the namespace's opening brace to the first body line. - /// + /// Advances past the namespace's opening brace to the first body line. /// The file lines. /// The current line index, advanced past the opening brace. private static void SkipToBodyStart(string[] lines, ref int i) @@ -282,17 +265,10 @@ private static void SkipToBodyStart(string[] lines, ref int i) bodyEnd--; } - if (bodyStart > bodyEnd) - { - return null; - } - - return string.Join(Environment.NewLine, lines[bodyStart..(bodyEnd + 1)]); + return bodyStart > bodyEnd ? null : string.Join(Environment.NewLine, lines[bodyStart..(bodyEnd + 1)]); } - /// - /// Updates the running brace depth for a single line, stopping at the matching close brace. - /// + /// Updates the running brace depth for a single line, stopping at the matching close brace. /// The line to scan. /// The current brace depth. /// The updated brace depth (zero once the matching close brace is found). @@ -317,9 +293,7 @@ private static int UpdateBraceDepth(string line, int braceDepth) return braceDepth; } - /// - /// Extracts the prefix from a using directive for grouping. - /// + /// Extracts the prefix from a using directive for grouping. /// The using directive. /// The prefix string. private static string ExtractUsingPrefix(string usingDirective) @@ -343,26 +317,18 @@ private static string ExtractUsingPrefix(string usingDirective) [GeneratedRegex(@"^using\s+(?:static\s+)?(\w+)")] private static partial Regex UsingPrefixRegex(); - /// - /// A set that preserves insertion order while preventing duplicates. - /// + /// A set that preserves insertion order while preventing duplicates. /// The element type. private sealed class LinkedHashSet : IEnumerable where T : notnull { - /// - /// The hash set used for O(1) duplicate checks. - /// + /// The hash set used for O(1) duplicate checks. private readonly HashSet _set = []; - /// - /// The list used for preserving insertion order. - /// + /// The list used for preserving insertion order. private readonly List _list = []; - /// - /// Adds an item to the set if it's not already present. - /// + /// Adds an item to the set if it's not already present. /// The item to add. public void Add(T item) { @@ -374,9 +340,7 @@ public void Add(T item) _list.Add(item); } - /// - /// Converts the set to a list. - /// + /// Converts the set to a list. /// A new list containing the set elements in insertion order. public List ToList() => [.. _list]; diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/SymbolHelpersTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/SymbolHelpersTests.cs index a3182df..83bdd69 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/SymbolHelpersTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/SymbolHelpersTests.cs @@ -10,14 +10,10 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests; -/// -/// Tests for methods. -/// +/// Tests for methods. public class SymbolHelpersTests { - /// - /// Verifies GetWellKnownSymbols resolves INPC symbol from a compilation. - /// + /// Verifies GetWellKnownSymbols resolves INPC symbol from a compilation. /// A task representing the asynchronous test operation. [Test] public async Task GetWellKnownSymbols_ResolvesINPC() @@ -35,9 +31,7 @@ namespace TestApp { public class Dummy {} } await Assert.That(symbols.INPC!.Name).IsEqualTo("INotifyPropertyChanged"); } - /// - /// Verifies GetWellKnownSymbols returns cached instance for same compilation. - /// + /// Verifies GetWellKnownSymbols returns cached instance for same compilation. /// A task representing the asynchronous test operation. [Test] public async Task GetWellKnownSymbols_SameCompilation_ReturnsCachedInstance() @@ -52,9 +46,7 @@ public async Task GetWellKnownSymbols_SameCompilation_ReturnsCachedInstance() await Assert.That(ReferenceEquals(symbols1, symbols2)).IsTrue(); } - /// - /// Verifies IsIObservable returns true for a direct IObservable<T> type. - /// + /// Verifies IsIObservable returns true for a direct IObservable<T> type. /// A task representing the asynchronous test operation. [Test] public async Task IsIObservable_DirectIObservableType_ReturnsTrue() @@ -77,9 +69,7 @@ public class MyVm { public IObservable Obs { get; set; } } await Assert.That(result).IsTrue(); } - /// - /// Verifies IsIObservable returns false for a non-observable type. - /// + /// Verifies IsIObservable returns false for a non-observable type. /// A task representing the asynchronous test operation. [Test] public async Task IsIObservable_NonObservableType_ReturnsFalse() @@ -101,9 +91,7 @@ public class MyVm { public string Name { get; set; } = ""; } await Assert.That(result).IsFalse(); } - /// - /// Verifies IsInteractionType returns true for a direct IInteraction<TInput,TOutput> type. - /// + /// Verifies IsInteractionType returns true for a direct IInteraction<TInput,TOutput> type. /// A task representing the asynchronous test operation. [Test] public async Task IsInteractionType_DirectIInteractionType_ReturnsTrue() @@ -126,9 +114,7 @@ public class MyVm { public IInteraction Confirm { get; set; } } await Assert.That(result).IsTrue(); } - /// - /// Verifies IsInteractionType returns false for a non-interaction type. - /// + /// Verifies IsInteractionType returns false for a non-interaction type. /// A task representing the asynchronous test operation. [Test] public async Task IsInteractionType_NonInteractionType_ReturnsFalse() @@ -180,9 +166,7 @@ public class MyVm { public IInteraction Confirm { get; set; } } await Assert.That(outputType).IsEqualTo("bool"); } - /// - /// Verifies ExtractInteractionTypeArguments returns false when the type is not an interaction type. - /// + /// Verifies ExtractInteractionTypeArguments returns false when the type is not an interaction type. /// A task representing the asynchronous test operation. [Test] public async Task ExtractInteractionTypeArguments_NonInteractionType_ReturnsFalse() @@ -294,9 +278,7 @@ public void Test() await Assert.That(innerType).IsEqualTo(leafSegment.PropertyTypeFullName); } - /// - /// Verifies DetectHasConverterOverride returns true when a parameter is typed as IBindingTypeConverter. - /// + /// Verifies DetectHasConverterOverride returns true when a parameter is typed as IBindingTypeConverter. /// A task representing the asynchronous test operation. [Test] public async Task DetectHasConverterOverride_WithIBindingTypeConverterParam_ReturnsTrue() @@ -316,7 +298,7 @@ public static void Bind(IBindingTypeConverter converter) { } var tree = compilation.SyntaxTrees.First(); var semanticModel = compilation.GetSemanticModel(tree); var classDecl = (await tree.GetRootAsync()).DescendantNodes().OfType() - .First(c => c.Identifier.Text == "Ext"); + .First(static c => c.Identifier.Text == "Ext"); var classSymbol = (INamedTypeSymbol)semanticModel.GetDeclaredSymbol(classDecl)!; var methodSymbol = classSymbol.GetMembers("Bind").OfType().First(); var converterParam = methodSymbol.Parameters[0]; @@ -326,9 +308,7 @@ public static void Bind(IBindingTypeConverter converter) { } await Assert.That(result).IsTrue(); } - /// - /// Verifies DetectHasConverterOverride returns false when a parameter has a Func type. - /// + /// Verifies DetectHasConverterOverride returns false when a parameter has a Func type. /// A task representing the asynchronous test operation. [Test] public async Task DetectHasConverterOverride_WithFuncParam_ReturnsFalse() @@ -348,7 +328,7 @@ public static void Bind(Func converter) { } var tree = compilation.SyntaxTrees.First(); var semanticModel = compilation.GetSemanticModel(tree); var classDecl = (await tree.GetRootAsync()).DescendantNodes().OfType() - .First(c => c.Identifier.Text == "Ext"); + .First(static c => c.Identifier.Text == "Ext"); var classSymbol = (INamedTypeSymbol)semanticModel.GetDeclaredSymbol(classDecl)!; var methodSymbol = classSymbol.GetMembers("Bind").OfType().First(); var converterParam = methodSymbol.Parameters[0]; @@ -358,9 +338,7 @@ public static void Bind(Func converter) { } await Assert.That(result).IsFalse(); } - /// - /// Verifies ResolveNamedType returns null when the lambda has a block body. - /// + /// Verifies ResolveNamedType returns null when the lambda has a block body. /// A task representing the asynchronous test operation. [Test] public async Task ResolveNamedType_BlockBodyLambda_ReturnsNull() @@ -421,9 +399,7 @@ public void Test() await Assert.That(result).IsNull(); } - /// - /// Verifies ResolveNamedType returns null when the expression is not a lambda expression. - /// + /// Verifies ResolveNamedType returns null when the expression is not a lambda expression. /// A task representing the asynchronous test operation. [Test] public async Task ResolveNamedType_NonLambdaExpression_ReturnsNull() @@ -460,9 +436,7 @@ public void Test() await Assert.That(result).IsNull(); } - /// - /// Gets a named type symbol from a compilation. - /// + /// Gets a named type symbol from a compilation. /// The compilation. /// The type name. /// The named type symbol. diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/SyntaxHelpersTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/SyntaxHelpersTests.cs index 30cdd6c..48f0906 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/SyntaxHelpersTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/SyntaxHelpersTests.cs @@ -8,14 +8,10 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests; -/// -/// Tests for methods. -/// +/// Tests for methods. public class SyntaxHelpersTests { - /// - /// Verifies ExtractPropertyPathFromLambda extracts a single property path from a lambda expression. - /// + /// Verifies ExtractPropertyPathFromLambda extracts a single property path from a lambda expression. /// A task representing the asynchronous test operation. [Test] public async Task ExtractPropertyPathFromLambda_SingleProperty_ExtractsPath() @@ -56,13 +52,12 @@ public void Test() await Assert.That(path[0].PropertyName).IsEqualTo("Name"); } - /// - /// Verifies ExtractPropertyPathFromLambda extracts a chained property path. - /// + /// Verifies ExtractPropertyPathFromLambda extracts a chained property path. /// A task representing the asynchronous test operation. [Test] public async Task ExtractPropertyPathFromLambda_ChainedProperty_ExtractsFullPath() { + const int Expected = 2; const string source = """ using System; using System.ComponentModel; @@ -100,14 +95,12 @@ public void Test() var path = SyntaxHelpers.ExtractPropertyPathFromLambda(lambda, semanticModel, default); await Assert.That(path).IsNotNull(); - await Assert.That(path!.Length).IsEqualTo(2); + await Assert.That(path!.Length).IsEqualTo(Expected); await Assert.That(path[0].PropertyName).IsEqualTo("Address"); await Assert.That(path[1].PropertyName).IsEqualTo("City"); } - /// - /// Verifies ExtractPropertyPathFromLambda returns null for non-lambda expression. - /// + /// Verifies ExtractPropertyPathFromLambda returns null for non-lambda expression. /// A task representing the asynchronous test operation. [Test] public async Task ExtractPropertyPathFromLambda_NonLambda_ReturnsNull() @@ -139,9 +132,7 @@ public void Test() await Assert.That(path).IsNull(); } - /// - /// Verifies GetLambdaBody returns the body for a simple lambda expression. - /// + /// Verifies GetLambdaBody returns the body for a simple lambda expression. /// A task representing the asynchronous test operation. [Test] public async Task GetLambdaBody_SimpleLambda_ReturnsBody() @@ -170,9 +161,7 @@ public void Test() await Assert.That(body).IsTypeOf(); } - /// - /// Verifies GetLambdaBody returns the body for a parenthesized lambda expression. - /// + /// Verifies GetLambdaBody returns the body for a parenthesized lambda expression. /// A task representing the asynchronous test operation. [Test] public async Task GetLambdaBody_ParenthesizedLambda_ReturnsBody() @@ -201,9 +190,7 @@ public void Test() await Assert.That(body).IsTypeOf(); } - /// - /// Verifies GetLambdaBody returns null for a parenthesized lambda with a block body. - /// + /// Verifies GetLambdaBody returns null for a parenthesized lambda with a block body. /// A task representing the asynchronous test operation. [Test] public async Task GetLambdaBody_BlockBody_ReturnsNull() @@ -231,9 +218,7 @@ public void Test() await Assert.That(body).IsNull(); } - /// - /// Verifies ExtractPropertyPathFromLambda works with parenthesized lambda expressions. - /// + /// Verifies ExtractPropertyPathFromLambda works with parenthesized lambda expressions. /// A task representing the asynchronous test operation. [Test] public async Task ExtractPropertyPathFromLambda_ParenthesizedLambda_ExtractsPath() diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/TestHelper.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/TestHelper.cs index 5648f90..bc46fad 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/TestHelper.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/TestHelper.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for full license information. using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.CompilerServices; using Microsoft.CodeAnalysis; @@ -30,17 +31,12 @@ public static class TestHelper public static LanguageVersion FallbackLanguageVersion(bool nullableEnabled) => nullableEnabled ? LanguageVersion.CSharp8 : LanguageVersion.CSharp7_3; - /// - /// Creates a compilation from source code, targeting C# 7.3 to verify generated output compatibility. - /// + /// Creates a compilation from source code, targeting C# 7.3 to verify generated output compatibility. /// The source code to compile. /// A compilation ready for testing. public static Compilation CreateCompilation(string source) => CreateCompilation(source, null); - /// - /// Creates a compilation from source code with appropriate references. - /// Includes ReactiveUI for IReactiveObject testing. - /// + /// Creates a compilation from source code with appropriate references. Includes ReactiveUI for IReactiveObject testing. /// The source code to compile. /// The C# language version to target, or for C# 7.3. /// A compilation ready for testing. @@ -52,20 +48,22 @@ public static Compilation CreateCompilation(string source, LanguageVersion? lang var syntaxTree = CSharpSyntaxTree.ParseText(source, parseOptions); - IEnumerable references; - #if NET10_0_OR_GREATER - references = Basic.Reference.Assemblies.Net100.References.All; + IEnumerable references = Basic.Reference.Assemblies.Net100.References.All; #elif NET9_0_OR_GREATER - references = Basic.Reference.Assemblies.Net90.References.All; + IEnumerable references = Basic.Reference.Assemblies.Net90.References.All; #else - references = Basic.Reference.Assemblies.Net80.References.All; + IEnumerable references = Basic.Reference.Assemblies.Net80.References.All; #endif - // Add ReactiveUI and transitive assembly references + // Add ReactiveUI and transitive assembly references. + // ReactiveUI is seeded by ReactiveObject rather than IReactiveObject: the two live in + // different assemblies, and the walk only follows references outward, so seeding from the + // interface would leave the assembly that declares ReactiveObject out of the compilation. var seedAssemblies = new[] { - typeof(IReactiveObject).Assembly, typeof(System.Reactive.Linq.Observable).Assembly, + typeof(ReactiveObject).Assembly, typeof(IReactiveObject).Assembly, + typeof(System.Reactive.Linq.Observable).Assembly, typeof(ReactiveUIBindingExtensions).Assembly, typeof(Reactive.ObserveOnObservable<>).Assembly }; @@ -78,10 +76,7 @@ public static Compilation CreateCompilation(string source, LanguageVersion? lang new(OutputKind.DynamicallyLinkedLibrary)); } - /// - /// Tests a source generator scenario that is expected to succeed. - /// Verifies the generated output against a snapshot. - /// + /// Tests a source generator scenario that is expected to succeed. Verifies the generated output against a snapshot. /// The source code to compile and generate. /// The type of the calling test class for snapshot organization. /// The source file path of the caller (automatically populated). @@ -91,8 +86,8 @@ public static Task TestPass( string source, Type callerType, [CallerFilePath] string file = "", - [CallerMemberName] string memberName = "") - => TestPass(source, callerType, null, file, memberName); + [CallerMemberName] string memberName = "") => + TestPass(source, callerType, null, file, memberName); /// /// Tests a source generator scenario that is expected to succeed, targeting a specific language version. @@ -119,12 +114,12 @@ public static Task TestPass( // Log any diagnostics for debugging var allDiagnostics = result.OutputCompilation.GetDiagnostics() .Concat(result.GeneratorDiagnostics) - .Where(d => d.Severity >= DiagnosticSeverity.Warning) + .Where(static d => d.Severity >= DiagnosticSeverity.Warning) .ToImmutableArray(); foreach (var diagnostic in allDiagnostics) { - Console.WriteLine($"{diagnostic.Severity}: {diagnostic.GetMessage()}"); + TestContext.Current?.OutputWriter.WriteLine($"{diagnostic.Severity}: {diagnostic.GetMessage()}"); } VerifySettings settings = new(); @@ -147,8 +142,8 @@ public static Task TestPassWithResult( string source, Type callerType, [CallerFilePath] string file = "", - [CallerMemberName] string memberName = "") - => TestPassWithResult(source, callerType, null, file, memberName); + [CallerMemberName] string memberName = "") => + TestPassWithResult(source, callerType, null, file, memberName); /// /// Tests a source generator scenario that is expected to succeed, targeting a specific language version. @@ -175,12 +170,16 @@ public static async Task TestPassWithResult( // Log any diagnostics for debugging var allDiagnostics = result.OutputCompilation.GetDiagnostics() .Concat(result.GeneratorDiagnostics) - .Where(d => d.Severity >= DiagnosticSeverity.Warning) + .Where(static d => d.Severity >= DiagnosticSeverity.Warning) .ToImmutableArray(); foreach (var diagnostic in allDiagnostics) { - Console.WriteLine($"{diagnostic.Severity}: {diagnostic.GetMessage()}"); + var writer = TestContext.Current?.OutputWriter; + if (writer is not null) + { + await writer.WriteLineAsync($"{diagnostic.Severity}: {diagnostic.GetMessage()}"); + } } VerifySettings settings = new(); @@ -192,16 +191,12 @@ public static async Task TestPassWithResult( return result; } - /// - /// Runs the source generator on the provided source code and returns the result. - /// + /// Runs the source generator on the provided source code and returns the result. /// The source code to compile and generate. /// A containing driver, compilation, and diagnostics. public static GeneratorTestResult RunGenerator(string source) => RunGenerator(source, null); - /// - /// Runs the source generator on the provided source code, targeting a specific language version. - /// + /// Runs the source generator on the provided source code, targeting a specific language version. /// The source code to compile and generate. /// The C# language version to target, or for C# 7.3. /// A containing driver, compilation, and diagnostics. @@ -229,12 +224,14 @@ public static GeneratorTestResult RunGenerator(string source, LanguageVersion? l return new(driver, outputCompilation, diagnostics); } - /// - /// Emits the output compilation to memory and loads it into a collectible assembly load context. - /// + /// Emits the output compilation to memory and loads it into a collectible assembly load context. /// The generator test result to emit. /// The loaded assembly and the load context (dispose context to unload). /// Thrown when emission fails. + [SuppressMessage( + "Security", + "SES1402:Assembly loaded from an unverifiable source", + Justification = "loads the compilation this test just emitted, in-process, into a collectible context")] public static (Assembly Assembly, CollectibleAssemblyLoadContext Context) EmitAndLoad(GeneratorTestResult result) { ArgumentNullException.ThrowIfNull(result); @@ -247,8 +244,8 @@ public static (Assembly Assembly, CollectibleAssemblyLoadContext Context) EmitAn var errors = string.Join( Environment.NewLine, emitResult.Diagnostics - .Where(d => d.Severity == DiagnosticSeverity.Error) - .Select(d => $" {d.Id}: {d.GetMessage()}")); + .Where(static d => d.Severity == DiagnosticSeverity.Error) + .Select(static d => $" {d.Id}: {d.GetMessage()}")); throw new InvalidOperationException( $"Failed to emit compilation:{Environment.NewLine}{errors}"); @@ -348,9 +345,14 @@ private static IEnumerable GetTransitiveReferences(params Ass { queue.Enqueue(System.Reflection.Assembly.Load(referencedName)); } - catch + catch (Exception e) { - // System assemblies already covered by Basic.Reference.Assemblies + // Reference discovery is best-effort: anything that will not load is already + // covered by the Basic.Reference.Assemblies framework set. The walk must carry + // on, because letting a load failure escape truncates the reference list and + // surfaces later as "type could not be found" in every generated compilation. + TestContext.Current?.OutputWriter.WriteLine( + $"skipped unresolvable reference '{referencedName.Name}': {e.Message}"); } } } diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/TypeDetectionExtractorTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/TypeDetectionExtractorTests.cs index 84add57..56ba499 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/TypeDetectionExtractorTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Helpers/TypeDetectionExtractorTests.cs @@ -9,18 +9,18 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests; -/// -/// Tests for methods. -/// +/// Tests for methods. public class TypeDetectionExtractorTests { - /// - /// Verifies ExtractProperties extracts public properties from a type symbol. - /// + /// The MyViewModel name these tests generate against. + private const string MyViewModelName = "MyViewModel"; + + /// Verifies ExtractProperties extracts public properties from a type symbol. /// A task representing the asynchronous test operation. [Test] public async Task ExtractProperties_PublicProperties_ExtractsAll() { + const int ExpectedPropertyCount = 2; const string source = """ using System.ComponentModel; @@ -36,16 +36,14 @@ public class MyViewModel : INotifyPropertyChanged """; var compilation = TestHelper.CreateCompilation(source); - var typeSymbol = GetNamedTypeSymbol(compilation, "MyViewModel"); + var typeSymbol = GetNamedTypeSymbol(compilation, MyViewModelName); var properties = TypeDetectionExtractor.ExtractProperties(typeSymbol, default); - await Assert.That(properties.Length).IsEqualTo(2); + await Assert.That(properties.Length).IsEqualTo(ExpectedPropertyCount); } - /// - /// Verifies ExtractProperties skips static properties. - /// + /// Verifies ExtractProperties skips static properties. /// A task representing the asynchronous test operation. [Test] public async Task ExtractProperties_StaticProperty_Skipped() @@ -65,7 +63,7 @@ public class MyViewModel : INotifyPropertyChanged """; var compilation = TestHelper.CreateCompilation(source); - var typeSymbol = GetNamedTypeSymbol(compilation, "MyViewModel"); + var typeSymbol = GetNamedTypeSymbol(compilation, MyViewModelName); var properties = TypeDetectionExtractor.ExtractProperties(typeSymbol, default); @@ -74,9 +72,7 @@ public class MyViewModel : INotifyPropertyChanged await Assert.That(properties[0].PropertyName).IsEqualTo("Name"); } - /// - /// Verifies ExtractProperties skips write-only properties. - /// + /// Verifies ExtractProperties skips write-only properties. /// A task representing the asynchronous test operation. [Test] public async Task ExtractProperties_WriteOnlyProperty_Skipped() @@ -97,7 +93,7 @@ public class MyViewModel : INotifyPropertyChanged """; var compilation = TestHelper.CreateCompilation(source); - var typeSymbol = GetNamedTypeSymbol(compilation, "MyViewModel"); + var typeSymbol = GetNamedTypeSymbol(compilation, MyViewModelName); var properties = TypeDetectionExtractor.ExtractProperties(typeSymbol, default); @@ -106,13 +102,12 @@ public class MyViewModel : INotifyPropertyChanged await Assert.That(properties[0].PropertyName).IsEqualTo("Title"); } - /// - /// Verifies ExtractProperties includes indexer properties with IsIndexer flag. - /// + /// Verifies ExtractProperties includes indexer properties with IsIndexer flag. /// A task representing the asynchronous test operation. [Test] public async Task ExtractProperties_Indexer_Included() { + const int ExpectedPropertyCount = 2; const string source = """ using System.ComponentModel; @@ -128,19 +123,17 @@ public class MyViewModel : INotifyPropertyChanged """; var compilation = TestHelper.CreateCompilation(source); - var typeSymbol = GetNamedTypeSymbol(compilation, "MyViewModel"); + var typeSymbol = GetNamedTypeSymbol(compilation, MyViewModelName); var properties = TypeDetectionExtractor.ExtractProperties(typeSymbol, default); // Both the indexer and Name are included; the indexer has IsIndexer = true - var indexerProp = properties.FirstOrDefault(p => p.IsIndexer); - await Assert.That(properties.Length).IsEqualTo(2); + var indexerProp = properties.FirstOrDefault(static p => p.IsIndexer); + await Assert.That(properties.Length).IsEqualTo(ExpectedPropertyCount); await Assert.That(indexerProp).IsNotNull(); } - /// - /// Verifies ExtractProperties detects dependency properties via companion static field heuristic. - /// + /// Verifies ExtractProperties detects dependency properties via companion static field heuristic. /// A task representing the asynchronous test operation. [Test] public async Task ExtractProperties_DependencyPropertyHeuristic_DetectsDP() @@ -160,17 +153,15 @@ public class MyViewModel : INotifyPropertyChanged """; var compilation = TestHelper.CreateCompilation(source); - var typeSymbol = GetNamedTypeSymbol(compilation, "MyViewModel"); + var typeSymbol = GetNamedTypeSymbol(compilation, MyViewModelName); var properties = TypeDetectionExtractor.ExtractProperties(typeSymbol, default); - var titleProp = properties.First(p => p.PropertyName == "Title"); + var titleProp = properties.First(static p => p.PropertyName == "Title"); await Assert.That(titleProp.IsDependencyProperty).IsTrue(); } - /// - /// Gets a named type symbol from a compilation. - /// + /// Gets a named type symbol from a compilation. /// The compilation. /// The type name. /// The named type symbol. diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Models/EquatableArrayTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Models/EquatableArrayTests.cs index eb0211b..6566404 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Models/EquatableArrayTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Models/EquatableArrayTests.cs @@ -7,14 +7,22 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests.Models; -/// -/// Tests for methods. -/// +/// Tests for methods. public class EquatableArrayTests { - /// - /// Verifies ComputeHashCode returns 0 for null array. - /// + /// The fully qualified name of the Int32 type used by these tests. + private const string Int32TypeName = "global::System.Int32"; + + /// The fully qualified name of the String type used by these tests. + private const string StringTypeName = "global::System.String"; + + /// The fully qualified name of the global::T type used by these tests. + private const string GlobalTTypeName = "global::T"; + + /// The fully qualified name of the VM type used by these tests. + private const string VMTypeName = "global::TestApp.VM"; + + /// Verifies ComputeHashCode returns 0 for null array. /// A task representing the asynchronous test operation. [Test] public async Task ComputeHashCode_NullArray_ReturnsZero() @@ -24,30 +32,27 @@ public async Task ComputeHashCode_NullArray_ReturnsZero() await Assert.That(result).IsEqualTo(0); } - /// - /// Verifies ComputeHashCode returns consistent hash for empty array. - /// + /// Verifies ComputeHashCode returns consistent hash for empty array. /// A task representing the asynchronous test operation. [Test] public async Task ComputeHashCode_EmptyArray_ReturnsConsistentHash() { + const int Expected = 17; var hash1 = EquatableArray.ComputeHashCode([]); var hash2 = EquatableArray.ComputeHashCode([]); await Assert.That(hash1).IsEqualTo(hash2); - await Assert.That(hash1).IsEqualTo(17); // Hash seed with no elements + await Assert.That(hash1).IsEqualTo(Expected); // Hash seed with no elements } - /// - /// Verifies ComputeHashCode returns same hash for same content in different arrays. - /// + /// Verifies ComputeHashCode returns same hash for same content in different arrays. /// A task representing the asynchronous test operation. [Test] public async Task ComputeHashCode_SameContent_ReturnsSameHash() { - var seg = new PropertyPathSegment("Name", "global::System.String", "global::TestApp.VM", true); + var seg = new PropertyPathSegment("Name", StringTypeName, VMTypeName, true); var arr1 = new[] { seg }; - var arr2 = new[] { new PropertyPathSegment("Name", "global::System.String", "global::TestApp.VM", true) }; + var arr2 = new[] { new PropertyPathSegment("Name", StringTypeName, VMTypeName, true) }; var hash1 = EquatableArray.ComputeHashCode(arr1); var hash2 = EquatableArray.ComputeHashCode(arr2); @@ -55,15 +60,13 @@ public async Task ComputeHashCode_SameContent_ReturnsSameHash() await Assert.That(hash1).IsEqualTo(hash2); } - /// - /// Verifies ComputeHashCode returns different hash for different content. - /// + /// Verifies ComputeHashCode returns different hash for different content. /// A task representing the asynchronous test operation. [Test] public async Task ComputeHashCode_DifferentContent_ReturnsDifferentHash() { - var arr1 = new[] { new PropertyPathSegment("Name", "global::System.String", "global::TestApp.VM", true) }; - var arr2 = new[] { new PropertyPathSegment("Age", "global::System.Int32", "global::TestApp.VM", false) }; + var arr1 = new[] { new PropertyPathSegment("Name", StringTypeName, VMTypeName, true) }; + var arr2 = new[] { new PropertyPathSegment("Age", Int32TypeName, VMTypeName, false) }; var hash1 = EquatableArray.ComputeHashCode(arr1); var hash2 = EquatableArray.ComputeHashCode(arr2); @@ -71,14 +74,12 @@ public async Task ComputeHashCode_DifferentContent_ReturnsDifferentHash() await Assert.That(hash1).IsNotEqualTo(hash2); } - /// - /// Verifies EquatableArray constructor caches hash code matching ComputeHashCode. - /// + /// Verifies EquatableArray constructor caches hash code matching ComputeHashCode. /// A task representing the asynchronous test operation. [Test] public async Task Constructor_CachesHashCode_MatchesComputeHashCode() { - var seg = new PropertyPathSegment("Name", "global::System.String", "global::TestApp.VM", true); + var seg = new PropertyPathSegment("Name", StringTypeName, VMTypeName, true); var arr = new[] { seg }; var equatable = new EquatableArray(arr); @@ -87,9 +88,7 @@ public async Task Constructor_CachesHashCode_MatchesComputeHashCode() await Assert.That(equatable.GetHashCode()).IsEqualTo(expected); } - /// - /// Verifies default-constructed EquatableArray has hash code 0. - /// + /// Verifies default-constructed EquatableArray has hash code 0. /// A task representing the asynchronous test operation. [Test] public async Task DefaultConstructed_HashCode_ReturnsZero() @@ -99,39 +98,33 @@ public async Task DefaultConstructed_HashCode_ReturnsZero() await Assert.That(defaultArray.GetHashCode()).IsEqualTo(0); } - /// - /// Verifies equal arrays are equal via Equals method. - /// + /// Verifies equal arrays are equal via Equals method. /// A task representing the asynchronous test operation. [Test] public async Task Equals_SameContent_ReturnsTrue() { var arr1 = new EquatableArray( - [new("Name", "global::System.String", "global::TestApp.VM", true)]); + [new("Name", StringTypeName, VMTypeName, true)]); var arr2 = new EquatableArray( - [new("Name", "global::System.String", "global::TestApp.VM", true)]); + [new("Name", StringTypeName, VMTypeName, true)]); await Assert.That(arr1.Equals(arr2)).IsTrue(); } - /// - /// Verifies different arrays are not equal via Equals method. - /// + /// Verifies different arrays are not equal via Equals method. /// A task representing the asynchronous test operation. [Test] public async Task Equals_DifferentContent_ReturnsFalse() { var arr1 = new EquatableArray( - [new("Name", "global::System.String", "global::TestApp.VM", true)]); + [new("Name", StringTypeName, VMTypeName, true)]); var arr2 = new EquatableArray( - [new("Age", "global::System.Int32", "global::TestApp.VM", false)]); + [new("Age", Int32TypeName, VMTypeName, false)]); await Assert.That(arr1.Equals(arr2)).IsFalse(); } - /// - /// Verifies default arrays are equal to each other. - /// + /// Verifies default arrays are equal to each other. /// A task representing the asynchronous test operation. [Test] public async Task Equals_BothDefault_ReturnsTrue() @@ -142,24 +135,21 @@ public async Task Equals_BothDefault_ReturnsTrue() await Assert.That(arr1.Equals(arr2)).IsTrue(); } - /// - /// Verifies Length returns the number of elements. - /// + /// Verifies Length returns the number of elements. /// A task representing the asynchronous test operation. [Test] public async Task Length_MultipleElements_ReturnsCount() { + const int ExpectedArrCount = 2; var arr = new EquatableArray([ - new("A", "global::System.String", "global::T", true), - new("B", "global::System.Int32", "global::T", false) + new("A", StringTypeName, GlobalTTypeName, true), + new("B", Int32TypeName, GlobalTTypeName, false) ]); - await Assert.That(arr.Length).IsEqualTo(2); + await Assert.That(arr.Length).IsEqualTo(ExpectedArrCount); } - /// - /// Verifies Length returns 0 for default-constructed array. - /// + /// Verifies Length returns 0 for default-constructed array. /// A task representing the asynchronous test operation. [Test] public async Task Length_DefaultConstructed_ReturnsZero() @@ -177,7 +167,7 @@ public async Task Length_DefaultConstructed_ReturnsZero() [Test] public async Task ComputeHashCode_NullElements_UsesZeroForNullHashCode() { - var arr = new PropertyPathSegment?[] { null!, new("Name", "global::System.String", "global::T", true), null! }; + var arr = new PropertyPathSegment?[] { null!, new("Name", StringTypeName, GlobalTTypeName, true), null! }; // The hash should incorporate 0 for null elements and the actual hash for non-null var hash = EquatableArray.ComputeHashCode(arr!); @@ -189,155 +179,136 @@ public async Task ComputeHashCode_NullElements_UsesZeroForNullHashCode() // Verify it differs from an array with all non-null elements var nonNullArr = new[] { - new PropertyPathSegment("A", "global::System.String", "global::T", true), - new PropertyPathSegment("Name", "global::System.String", "global::T", true), - new PropertyPathSegment("B", "global::System.String", "global::T", true) + new PropertyPathSegment("A", StringTypeName, GlobalTTypeName, true), + new PropertyPathSegment("Name", StringTypeName, GlobalTTypeName, true), + new PropertyPathSegment("B", StringTypeName, GlobalTTypeName, true) }; var nonNullHash = EquatableArray.ComputeHashCode(nonNullArr); await Assert.That(hash).IsNotEqualTo(nonNullHash); } - /// - /// Verifies operator== returns true for equal arrays. - /// + /// Verifies operator== returns true for equal arrays. /// A task representing the asynchronous test operation. [Test] public async Task OperatorEquals_SameContent_ReturnsTrue() { var arr1 = new EquatableArray( - [new("Name", "global::System.String", "global::T", true)]); + [new("Name", StringTypeName, GlobalTTypeName, true)]); var arr2 = new EquatableArray( - [new("Name", "global::System.String", "global::T", true)]); + [new("Name", StringTypeName, GlobalTTypeName, true)]); await Assert.That(arr1 == arr2).IsTrue(); } - /// - /// Verifies operator!= returns true for different arrays. - /// + /// Verifies operator!= returns true for different arrays. /// A task representing the asynchronous test operation. [Test] public async Task OperatorNotEquals_DifferentContent_ReturnsTrue() { var arr1 = new EquatableArray( - [new("Name", "global::System.String", "global::T", true)]); + [new("Name", StringTypeName, GlobalTTypeName, true)]); var arr2 = new EquatableArray( - [new("Age", "global::System.Int32", "global::T", false)]); + [new("Age", Int32TypeName, GlobalTTypeName, false)]); await Assert.That(arr1 != arr2).IsTrue(); } - /// - /// Verifies the indexer returns the correct element at each position. - /// + /// Verifies the indexer returns the correct element at each position. /// A task representing the asynchronous test operation. [Test] public async Task Indexer_ReturnsCorrectElement() { - var seg0 = new PropertyPathSegment("Name", "global::System.String", "global::TestApp.VM", true); - var seg1 = new PropertyPathSegment("Age", "global::System.Int32", "global::TestApp.VM", false); + var seg0 = new PropertyPathSegment("Name", StringTypeName, VMTypeName, true); + var seg1 = new PropertyPathSegment("Age", Int32TypeName, VMTypeName, false); var arr = new EquatableArray([seg0, seg1]); await Assert.That(arr[0]).IsEqualTo(seg0); await Assert.That(arr[1]).IsEqualTo(seg1); } - /// - /// Verifies Equals(object) returns true when passed an equal EquatableArray boxed as object. - /// + /// Verifies Equals(object) returns true when passed an equal EquatableArray boxed as object. /// A task representing the asynchronous test operation. [Test] public async Task Equals_ObjectOverload_WithSameType_ReturnsTrue() { var arr1 = new EquatableArray( - [new("Name", "global::System.String", "global::TestApp.VM", true)]); + [new("Name", StringTypeName, VMTypeName, true)]); object obj = new EquatableArray( - [new("Name", "global::System.String", "global::TestApp.VM", true)]); + [new("Name", StringTypeName, VMTypeName, true)]); await Assert.That(arr1.Equals(obj)).IsTrue(); } - /// - /// Verifies Equals(object) returns false when passed a different type. - /// + /// Verifies Equals(object) returns false when passed a different type. /// A task representing the asynchronous test operation. [Test] public async Task Equals_ObjectOverload_WithDifferentType_ReturnsFalse() { var arr1 = new EquatableArray( - [new("Name", "global::System.String", "global::TestApp.VM", true)]); + [new("Name", StringTypeName, VMTypeName, true)]); await Assert.That(arr1.Equals("not an array")).IsFalse(); } - /// - /// Verifies Equals(object) returns false when passed null. - /// + /// Verifies Equals(object) returns false when passed null. /// A task representing the asynchronous test operation. [Test] public async Task Equals_ObjectOverload_WithNull_ReturnsFalse() { var arr1 = new EquatableArray( - [new("Name", "global::System.String", "global::TestApp.VM", true)]); + [new("Name", StringTypeName, VMTypeName, true)]); await Assert.That(arr1.Equals((object?)null)).IsFalse(); } - /// - /// Verifies a default array is not equal to a non-default array. - /// + /// Verifies a default array is not equal to a non-default array. /// A task representing the asynchronous test operation. [Test] public async Task Equals_DefaultVsNonDefault_ReturnsFalse() { var defaultArr = default(EquatableArray); var nonDefaultArr = new EquatableArray( - [new("Name", "global::System.String", "global::TestApp.VM", true)]); + [new("Name", StringTypeName, VMTypeName, true)]); await Assert.That(defaultArr.Equals(nonDefaultArr)).IsFalse(); } - /// - /// Verifies arrays with different lengths are not equal. - /// + /// Verifies arrays with different lengths are not equal. /// A task representing the asynchronous test operation. [Test] public async Task Equals_DifferentLengths_ReturnsFalse() { var arr1 = new EquatableArray( - [new("Name", "global::System.String", "global::TestApp.VM", true)]); + [new("Name", StringTypeName, VMTypeName, true)]); var arr2 = new EquatableArray([ - new("Name", "global::System.String", "global::TestApp.VM", true), - new("Age", "global::System.Int32", "global::TestApp.VM", false) + new("Name", StringTypeName, VMTypeName, true), + new("Age", Int32TypeName, VMTypeName, false) ]); await Assert.That(arr1.Equals(arr2)).IsFalse(); } - /// - /// Verifies the generic enumerator iterates all elements in order. - /// + /// Verifies the generic enumerator iterates all elements in order. /// A task representing the asynchronous test operation. [Test] public async Task GetEnumerator_IteratesAllElements() { - var seg0 = new PropertyPathSegment("A", "global::System.String", "global::TestApp.VM", true); - var seg1 = new PropertyPathSegment("B", "global::System.Int32", "global::TestApp.VM", false); - var seg2 = new PropertyPathSegment("C", "global::System.Boolean", "global::TestApp.VM", false); + const int ExpectedListCount = 3; + var seg0 = new PropertyPathSegment("A", StringTypeName, VMTypeName, true); + var seg1 = new PropertyPathSegment("B", Int32TypeName, VMTypeName, false); + var seg2 = new PropertyPathSegment("C", "global::System.Boolean", VMTypeName, false); var arr = new EquatableArray([seg0, seg1, seg2]); var list = arr.ToList(); - await Assert.That(list.Count).IsEqualTo(3); + await Assert.That(list.Count).IsEqualTo(ExpectedListCount); await Assert.That(list[0]).IsEqualTo(seg0); await Assert.That(list[1]).IsEqualTo(seg1); await Assert.That(list[2]).IsEqualTo(seg2); } - /// - /// Verifies iterating a default-constructed array yields no elements. - /// + /// Verifies iterating a default-constructed array yields no elements. /// A task representing the asynchronous test operation. [Test] public async Task GetEnumerator_DefaultArray_IteratesNothing() @@ -353,16 +324,15 @@ public async Task GetEnumerator_DefaultArray_IteratesNothing() await Assert.That(count).IsEqualTo(0); } - /// - /// Verifies the non-generic IEnumerable.GetEnumerator works correctly. - /// + /// Verifies the non-generic IEnumerable.GetEnumerator works correctly. /// A task representing the asynchronous test operation. [Test] public async Task NonGenericGetEnumerator_Works() { + const int Expected = 2; var arr = new EquatableArray([ - new("Name", "global::System.String", "global::TestApp.VM", true), - new("Age", "global::System.Int32", "global::TestApp.VM", false) + new("Name", StringTypeName, VMTypeName, true), + new("Age", Int32TypeName, VMTypeName, false) ]); var enumerator = ((IEnumerable)arr).GetEnumerator(); @@ -372,12 +342,10 @@ public async Task NonGenericGetEnumerator_Works() count++; } - await Assert.That(count).IsEqualTo(2); + await Assert.That(count).IsEqualTo(Expected); } - /// - /// Verifies operator== returns true for two default-constructed instances. - /// + /// Verifies operator== returns true for two default-constructed instances. /// A task representing the asynchronous test operation. [Test] public async Task OperatorEquals_BothDefault_ReturnsTrue() @@ -388,17 +356,15 @@ public async Task OperatorEquals_BothDefault_ReturnsTrue() await Assert.That(arr1 == arr2).IsTrue(); } - /// - /// Verifies operator!= returns false for arrays with the same content. - /// + /// Verifies operator!= returns false for arrays with the same content. /// A task representing the asynchronous test operation. [Test] public async Task OperatorNotEquals_SameContent_ReturnsFalse() { var arr1 = new EquatableArray( - [new("Name", "global::System.String", "global::TestApp.VM", true)]); + [new("Name", StringTypeName, VMTypeName, true)]); var arr2 = new EquatableArray( - [new("Name", "global::System.String", "global::TestApp.VM", true)]); + [new("Name", StringTypeName, VMTypeName, true)]); await Assert.That(arr1 != arr2).IsFalse(); } diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Models/ModelEqualityTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Models/ModelEqualityTests.cs index 39f460c..2b79263 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Models/ModelEqualityTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Models/ModelEqualityTests.cs @@ -8,142 +8,144 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests.Models; -/// -/// Tests for auto-generated record equality members on internal model types: -/// , , -/// , , -/// , and . -/// +/// Tests the auto-generated record equality members on the internal pipeline model types. public class ModelEqualityTests { + /// The fully qualified name of the Int32 type used by these tests. + private const string Int32TypeName = "global::System.Int32"; + + /// The fully qualified name of the String type used by these tests. + private const string StringTypeName = "global::System.String"; + + /// The fully qualified name of the MyViewModel type used by these tests. + private const string MyViewModelTypeName = "global::TestApp.MyViewModel"; + + /// The MyViewModel name these tests generate against. + private const string MyViewModelName = "MyViewModel"; + + /// The string name these tests generate against. + private const string StringName = "string"; + // ─────────────────────────────────────────────────────────────────────────── // ObservableTypeInfo // ─────────────────────────────────────────────────────────────────────────── - - /// - /// Verifies that two ObservableTypeInfo instances with identical values are equal. - /// + /// Verifies that two ObservableTypeInfo instances with identical values are equal. /// A task representing the asynchronous test operation. [Test] public async Task ObservableTypeInfo_Equals_SameValues_ReturnsTrue() { + const int Affinity = 21; var properties = new EquatableArray([ - ModelFactory.CreateObservablePropertyInfo("Name") + ModelFactory.CreateObservablePropertyInfo() ]); - var a = new ObservableTypeInfo("global::TestApp.MyViewModel", "MyViewModel", "INPC", 21, true, properties); - var b = new ObservableTypeInfo("global::TestApp.MyViewModel", "MyViewModel", "INPC", 21, true, properties); + var a = new ObservableTypeInfo(MyViewModelTypeName, MyViewModelName, "INPC", Affinity, true, properties); + var b = new ObservableTypeInfo(MyViewModelTypeName, MyViewModelName, "INPC", Affinity, true, properties); await Assert.That(a.Equals(b)).IsTrue(); } - /// - /// Verifies that two ObservableTypeInfo instances with different values are not equal. - /// + /// Verifies that two ObservableTypeInfo instances with different values are not equal. /// A task representing the asynchronous test operation. [Test] public async Task ObservableTypeInfo_Equals_DifferentValues_ReturnsFalse() { + const int Affinity = 21; var properties = new EquatableArray([ - ModelFactory.CreateObservablePropertyInfo("Name") + ModelFactory.CreateObservablePropertyInfo() ]); - var a = new ObservableTypeInfo("global::TestApp.MyViewModel", "MyViewModel", "INPC", 21, true, properties); - var b = new ObservableTypeInfo("global::TestApp.OtherType", "OtherType", "INPC", 21, true, properties); + var a = new ObservableTypeInfo(MyViewModelTypeName, MyViewModelName, "INPC", Affinity, true, properties); + var b = new ObservableTypeInfo("global::TestApp.OtherType", "OtherType", "INPC", Affinity, true, properties); await Assert.That(a.Equals(b)).IsFalse(); } - /// - /// Verifies that ObservableTypeInfo.Equals returns false when compared to null object. - /// + /// Verifies that ObservableTypeInfo.Equals returns false when compared to null object. /// A task representing the asynchronous test operation. [Test] public async Task ObservableTypeInfo_Equals_ObjectNull_ReturnsFalse() { + const int Affinity = 21; var properties = new EquatableArray([]); - var a = new ObservableTypeInfo("global::TestApp.MyViewModel", "MyViewModel", "INPC", 21, true, properties); + var a = new ObservableTypeInfo(MyViewModelTypeName, MyViewModelName, "INPC", Affinity, true, properties); await Assert.That(a.Equals(NullReference())).IsFalse(); } - /// - /// Verifies that ObservableTypeInfo.Equals returns false when compared to a different type. - /// + /// Verifies that ObservableTypeInfo.Equals returns false when compared to a different type. /// A task representing the asynchronous test operation. [Test] public async Task ObservableTypeInfo_Equals_ObjectWrongType_ReturnsFalse() { + const int Affinity = 21; var properties = new EquatableArray([]); - var a = new ObservableTypeInfo("global::TestApp.MyViewModel", "MyViewModel", "INPC", 21, true, properties); + var a = new ObservableTypeInfo(MyViewModelTypeName, MyViewModelName, "INPC", Affinity, true, properties); - await Assert.That(a.Equals("string")).IsFalse(); + await Assert.That(a.Equals(StringName)).IsFalse(); } - /// - /// Verifies that two ObservableTypeInfo instances with same values produce the same hash code. - /// + /// Verifies that two ObservableTypeInfo instances with same values produce the same hash code. /// A task representing the asynchronous test operation. [Test] public async Task ObservableTypeInfo_GetHashCode_SameValues_AreEqual() { + const int Affinity = 21; var properties = new EquatableArray([ - ModelFactory.CreateObservablePropertyInfo("Name") + ModelFactory.CreateObservablePropertyInfo() ]); - var a = new ObservableTypeInfo("global::TestApp.MyViewModel", "MyViewModel", "INPC", 21, true, properties); - var b = new ObservableTypeInfo("global::TestApp.MyViewModel", "MyViewModel", "INPC", 21, true, properties); + var a = new ObservableTypeInfo(MyViewModelTypeName, MyViewModelName, "INPC", Affinity, true, properties); + var b = new ObservableTypeInfo(MyViewModelTypeName, MyViewModelName, "INPC", Affinity, true, properties); await Assert.That(a.GetHashCode()).IsEqualTo(b.GetHashCode()); } - /// - /// Verifies that operator== returns true for ObservableTypeInfo instances with same values. - /// + /// Verifies that operator== returns true for ObservableTypeInfo instances with same values. /// A task representing the asynchronous test operation. [Test] public async Task ObservableTypeInfo_OperatorEquals_SameValues_ReturnsTrue() { + const int Affinity = 21; var properties = new EquatableArray([ - ModelFactory.CreateObservablePropertyInfo("Name") + ModelFactory.CreateObservablePropertyInfo() ]); - var a = new ObservableTypeInfo("global::TestApp.MyViewModel", "MyViewModel", "INPC", 21, true, properties); - var b = new ObservableTypeInfo("global::TestApp.MyViewModel", "MyViewModel", "INPC", 21, true, properties); + var a = new ObservableTypeInfo(MyViewModelTypeName, MyViewModelName, "INPC", Affinity, true, properties); + var b = new ObservableTypeInfo(MyViewModelTypeName, MyViewModelName, "INPC", Affinity, true, properties); await Assert.That(a == b).IsTrue(); } - /// - /// Verifies that operator!= returns true for ObservableTypeInfo instances with different values. - /// + /// Verifies that operator!= returns true for ObservableTypeInfo instances with different values. /// A task representing the asynchronous test operation. [Test] public async Task ObservableTypeInfo_OperatorNotEquals_DifferentValues_ReturnsTrue() { + const int Affinity = 21; + const int Affinity2 = 24; var properties = new EquatableArray([]); - var a = new ObservableTypeInfo("global::TestApp.MyViewModel", "MyViewModel", "INPC", 21, true, properties); + var a = new ObservableTypeInfo(MyViewModelTypeName, MyViewModelName, "INPC", Affinity, true, properties); var b = new ObservableTypeInfo( - "global::TestApp.MyViewModel", - "MyViewModel", + MyViewModelTypeName, + MyViewModelName, "ReactiveObject", - 24, + Affinity2, true, properties); await Assert.That(a != b).IsTrue(); } - /// - /// Verifies that ObservableTypeInfo.ToString contains the type name. - /// + /// Verifies that ObservableTypeInfo.ToString contains the type name. /// A task representing the asynchronous test operation. [Test] public async Task ObservableTypeInfo_ToString_ContainsTypeName() { + const int Affinity = 21; var properties = new EquatableArray([]); - var a = new ObservableTypeInfo("global::TestApp.MyViewModel", "MyViewModel", "INPC", 21, true, properties); + var a = new ObservableTypeInfo(MyViewModelTypeName, MyViewModelName, "INPC", Affinity, true, properties); await Assert.That(a.ToString()).Contains("ObservableTypeInfo"); } @@ -151,104 +153,87 @@ public async Task ObservableTypeInfo_ToString_ContainsTypeName() // ─────────────────────────────────────────────────────────────────────────── // ObservablePropertyInfo // ─────────────────────────────────────────────────────────────────────────── - - /// - /// Verifies that two ObservablePropertyInfo instances with identical values are equal. - /// + /// Verifies that two ObservablePropertyInfo instances with identical values are equal. /// A task representing the asynchronous test operation. [Test] public async Task ObservablePropertyInfo_Equals_SameValues_ReturnsTrue() { - var a = new ObservablePropertyInfo("Name", "global::System.String", true, false, false); - var b = new ObservablePropertyInfo("Name", "global::System.String", true, false, false); + var a = new ObservablePropertyInfo("Name", StringTypeName, true, false, false); + var b = new ObservablePropertyInfo("Name", StringTypeName, true, false, false); await Assert.That(a.Equals(b)).IsTrue(); } - /// - /// Verifies that two ObservablePropertyInfo instances with different values are not equal. - /// + /// Verifies that two ObservablePropertyInfo instances with different values are not equal. /// A task representing the asynchronous test operation. [Test] public async Task ObservablePropertyInfo_Equals_DifferentValues_ReturnsFalse() { - var a = new ObservablePropertyInfo("Name", "global::System.String", true, false, false); - var b = new ObservablePropertyInfo("Age", "global::System.Int32", true, false, false); + var a = new ObservablePropertyInfo("Name", StringTypeName, true, false, false); + var b = new ObservablePropertyInfo("Age", Int32TypeName, true, false, false); await Assert.That(a.Equals(b)).IsFalse(); } - /// - /// Verifies that ObservablePropertyInfo.Equals returns false when compared to null object. - /// + /// Verifies that ObservablePropertyInfo.Equals returns false when compared to null object. /// A task representing the asynchronous test operation. [Test] public async Task ObservablePropertyInfo_Equals_ObjectNull_ReturnsFalse() { - var a = new ObservablePropertyInfo("Name", "global::System.String", true, false, false); + var a = new ObservablePropertyInfo("Name", StringTypeName, true, false, false); await Assert.That(a.Equals(NullReference())).IsFalse(); } - /// - /// Verifies that ObservablePropertyInfo.Equals returns false when compared to a different type. - /// + /// Verifies that ObservablePropertyInfo.Equals returns false when compared to a different type. /// A task representing the asynchronous test operation. [Test] public async Task ObservablePropertyInfo_Equals_ObjectWrongType_ReturnsFalse() { - var a = new ObservablePropertyInfo("Name", "global::System.String", true, false, false); + var a = new ObservablePropertyInfo("Name", StringTypeName, true, false, false); - await Assert.That(a.Equals("string")).IsFalse(); + await Assert.That(a.Equals(StringName)).IsFalse(); } - /// - /// Verifies that two ObservablePropertyInfo instances with same values produce the same hash code. - /// + /// Verifies that two ObservablePropertyInfo instances with same values produce the same hash code. /// A task representing the asynchronous test operation. [Test] public async Task ObservablePropertyInfo_GetHashCode_SameValues_AreEqual() { - var a = new ObservablePropertyInfo("Name", "global::System.String", true, false, false); - var b = new ObservablePropertyInfo("Name", "global::System.String", true, false, false); + var a = new ObservablePropertyInfo("Name", StringTypeName, true, false, false); + var b = new ObservablePropertyInfo("Name", StringTypeName, true, false, false); await Assert.That(a.GetHashCode()).IsEqualTo(b.GetHashCode()); } - /// - /// Verifies that operator== returns true for ObservablePropertyInfo instances with same values. - /// + /// Verifies that operator== returns true for ObservablePropertyInfo instances with same values. /// A task representing the asynchronous test operation. [Test] public async Task ObservablePropertyInfo_OperatorEquals_SameValues_ReturnsTrue() { - var a = new ObservablePropertyInfo("Name", "global::System.String", true, false, false); - var b = new ObservablePropertyInfo("Name", "global::System.String", true, false, false); + var a = new ObservablePropertyInfo("Name", StringTypeName, true, false, false); + var b = new ObservablePropertyInfo("Name", StringTypeName, true, false, false); await Assert.That(a == b).IsTrue(); } - /// - /// Verifies that operator!= returns true for ObservablePropertyInfo instances with different values. - /// + /// Verifies that operator!= returns true for ObservablePropertyInfo instances with different values. /// A task representing the asynchronous test operation. [Test] public async Task ObservablePropertyInfo_OperatorNotEquals_DifferentValues_ReturnsTrue() { - var a = new ObservablePropertyInfo("Name", "global::System.String", true, false, false); - var b = new ObservablePropertyInfo("Name", "global::System.String", false, false, false); + var a = new ObservablePropertyInfo("Name", StringTypeName, true, false, false); + var b = new ObservablePropertyInfo("Name", StringTypeName, false, false, false); await Assert.That(a != b).IsTrue(); } - /// - /// Verifies that ObservablePropertyInfo.ToString contains the type name. - /// + /// Verifies that ObservablePropertyInfo.ToString contains the type name. /// A task representing the asynchronous test operation. [Test] public async Task ObservablePropertyInfo_ToString_ContainsTypeName() { - var a = new ObservablePropertyInfo("Name", "global::System.String", true, false, false); + var a = new ObservablePropertyInfo("Name", StringTypeName, true, false, false); await Assert.That(a.ToString()).Contains("ObservablePropertyInfo"); } @@ -256,10 +241,7 @@ public async Task ObservablePropertyInfo_ToString_ContainsTypeName() // ─────────────────────────────────────────────────────────────────────────── // InvocationInfo // ─────────────────────────────────────────────────────────────────────────── - - /// - /// Verifies that two InvocationInfo instances with identical values are equal. - /// + /// Verifies that two InvocationInfo instances with identical values are equal. /// A task representing the asynchronous test operation. [Test] public async Task InvocationInfo_Equals_SameValues_ReturnsTrue() @@ -270,22 +252,18 @@ public async Task InvocationInfo_Equals_SameValues_ReturnsTrue() await Assert.That(a.Equals(b)).IsTrue(); } - /// - /// Verifies that two InvocationInfo instances with different values are not equal. - /// + /// Verifies that two InvocationInfo instances with different values are not equal. /// A task representing the asynchronous test operation. [Test] public async Task InvocationInfo_Equals_DifferentValues_ReturnsFalse() { - var a = ModelFactory.CreateInvocationInfo(callerLineNumber: 42); + var a = ModelFactory.CreateInvocationInfo(); var b = ModelFactory.CreateInvocationInfo(callerLineNumber: 99); await Assert.That(a.Equals(b)).IsFalse(); } - /// - /// Verifies that InvocationInfo.Equals returns false when compared to null object. - /// + /// Verifies that InvocationInfo.Equals returns false when compared to null object. /// A task representing the asynchronous test operation. [Test] public async Task InvocationInfo_Equals_ObjectNull_ReturnsFalse() @@ -295,21 +273,17 @@ public async Task InvocationInfo_Equals_ObjectNull_ReturnsFalse() await Assert.That(a.Equals(NullReference())).IsFalse(); } - /// - /// Verifies that InvocationInfo.Equals returns false when compared to a different type. - /// + /// Verifies that InvocationInfo.Equals returns false when compared to a different type. /// A task representing the asynchronous test operation. [Test] public async Task InvocationInfo_Equals_ObjectWrongType_ReturnsFalse() { var a = ModelFactory.CreateInvocationInfo(); - await Assert.That(a.Equals("string")).IsFalse(); + await Assert.That(a.Equals(StringName)).IsFalse(); } - /// - /// Verifies that two InvocationInfo instances with same values produce the same hash code. - /// + /// Verifies that two InvocationInfo instances with same values produce the same hash code. /// A task representing the asynchronous test operation. [Test] public async Task InvocationInfo_GetHashCode_SameValues_AreEqual() @@ -320,9 +294,7 @@ public async Task InvocationInfo_GetHashCode_SameValues_AreEqual() await Assert.That(a.GetHashCode()).IsEqualTo(b.GetHashCode()); } - /// - /// Verifies that operator== returns true for InvocationInfo instances with same values. - /// + /// Verifies that operator== returns true for InvocationInfo instances with same values. /// A task representing the asynchronous test operation. [Test] public async Task InvocationInfo_OperatorEquals_SameValues_ReturnsTrue() @@ -333,22 +305,18 @@ public async Task InvocationInfo_OperatorEquals_SameValues_ReturnsTrue() await Assert.That(a == b).IsTrue(); } - /// - /// Verifies that operator!= returns true for InvocationInfo instances with different values. - /// + /// Verifies that operator!= returns true for InvocationInfo instances with different values. /// A task representing the asynchronous test operation. [Test] public async Task InvocationInfo_OperatorNotEquals_DifferentValues_ReturnsTrue() { - var a = ModelFactory.CreateInvocationInfo(methodName: "WhenChanged"); + var a = ModelFactory.CreateInvocationInfo(); var b = ModelFactory.CreateInvocationInfo(methodName: "WhenChanging"); await Assert.That(a != b).IsTrue(); } - /// - /// Verifies that InvocationInfo.ToString contains the type name. - /// + /// Verifies that InvocationInfo.ToString contains the type name. /// A task representing the asynchronous test operation. [Test] public async Task InvocationInfo_ToString_ContainsTypeName() @@ -361,10 +329,7 @@ public async Task InvocationInfo_ToString_ContainsTypeName() // ─────────────────────────────────────────────────────────────────────────── // BindingInvocationInfo // ─────────────────────────────────────────────────────────────────────────── - - /// - /// Verifies that two BindingInvocationInfo instances with identical values are equal. - /// + /// Verifies that two BindingInvocationInfo instances with identical values are equal. /// A task representing the asynchronous test operation. [Test] public async Task BindingInvocationInfo_Equals_SameValues_ReturnsTrue() @@ -375,22 +340,18 @@ public async Task BindingInvocationInfo_Equals_SameValues_ReturnsTrue() await Assert.That(a.Equals(b)).IsTrue(); } - /// - /// Verifies that two BindingInvocationInfo instances with different values are not equal. - /// + /// Verifies that two BindingInvocationInfo instances with different values are not equal. /// A task representing the asynchronous test operation. [Test] public async Task BindingInvocationInfo_Equals_DifferentValues_ReturnsFalse() { - var a = ModelFactory.CreateBindingInvocationInfo(isTwoWay: false); + var a = ModelFactory.CreateBindingInvocationInfo(); var b = ModelFactory.CreateBindingInvocationInfo(isTwoWay: true); await Assert.That(a.Equals(b)).IsFalse(); } - /// - /// Verifies that BindingInvocationInfo.Equals returns false when compared to null object. - /// + /// Verifies that BindingInvocationInfo.Equals returns false when compared to null object. /// A task representing the asynchronous test operation. [Test] public async Task BindingInvocationInfo_Equals_ObjectNull_ReturnsFalse() @@ -400,21 +361,17 @@ public async Task BindingInvocationInfo_Equals_ObjectNull_ReturnsFalse() await Assert.That(a.Equals(NullReference())).IsFalse(); } - /// - /// Verifies that BindingInvocationInfo.Equals returns false when compared to a different type. - /// + /// Verifies that BindingInvocationInfo.Equals returns false when compared to a different type. /// A task representing the asynchronous test operation. [Test] public async Task BindingInvocationInfo_Equals_ObjectWrongType_ReturnsFalse() { var a = ModelFactory.CreateBindingInvocationInfo(); - await Assert.That(a.Equals("string")).IsFalse(); + await Assert.That(a.Equals(StringName)).IsFalse(); } - /// - /// Verifies that two BindingInvocationInfo instances with same values produce the same hash code. - /// + /// Verifies that two BindingInvocationInfo instances with same values produce the same hash code. /// A task representing the asynchronous test operation. [Test] public async Task BindingInvocationInfo_GetHashCode_SameValues_AreEqual() @@ -425,9 +382,7 @@ public async Task BindingInvocationInfo_GetHashCode_SameValues_AreEqual() await Assert.That(a.GetHashCode()).IsEqualTo(b.GetHashCode()); } - /// - /// Verifies that operator== returns true for BindingInvocationInfo instances with same values. - /// + /// Verifies that operator== returns true for BindingInvocationInfo instances with same values. /// A task representing the asynchronous test operation. [Test] public async Task BindingInvocationInfo_OperatorEquals_SameValues_ReturnsTrue() @@ -438,22 +393,18 @@ public async Task BindingInvocationInfo_OperatorEquals_SameValues_ReturnsTrue() await Assert.That(a == b).IsTrue(); } - /// - /// Verifies that operator!= returns true for BindingInvocationInfo instances with different values. - /// + /// Verifies that operator!= returns true for BindingInvocationInfo instances with different values. /// A task representing the asynchronous test operation. [Test] public async Task BindingInvocationInfo_OperatorNotEquals_DifferentValues_ReturnsTrue() { - var a = ModelFactory.CreateBindingInvocationInfo(methodName: "BindOneWay"); + var a = ModelFactory.CreateBindingInvocationInfo(); var b = ModelFactory.CreateBindingInvocationInfo(methodName: "BindTwoWay"); await Assert.That(a != b).IsTrue(); } - /// - /// Verifies that BindingInvocationInfo.ToString contains the type name. - /// + /// Verifies that BindingInvocationInfo.ToString contains the type name. /// A task representing the asynchronous test operation. [Test] public async Task BindingInvocationInfo_ToString_ContainsTypeName() @@ -466,104 +417,87 @@ public async Task BindingInvocationInfo_ToString_ContainsTypeName() // ─────────────────────────────────────────────────────────────────────────── // PropertyPathSegment // ─────────────────────────────────────────────────────────────────────────── - - /// - /// Verifies that two PropertyPathSegment instances with identical values are equal. - /// + /// Verifies that two PropertyPathSegment instances with identical values are equal. /// A task representing the asynchronous test operation. [Test] public async Task PropertyPathSegment_Equals_SameValues_ReturnsTrue() { - var a = new PropertyPathSegment("Name", "global::System.String", "global::TestApp.MyViewModel", true); - var b = new PropertyPathSegment("Name", "global::System.String", "global::TestApp.MyViewModel", true); + var a = new PropertyPathSegment("Name", StringTypeName, MyViewModelTypeName, true); + var b = new PropertyPathSegment("Name", StringTypeName, MyViewModelTypeName, true); await Assert.That(a.Equals(b)).IsTrue(); } - /// - /// Verifies that two PropertyPathSegment instances with different values are not equal. - /// + /// Verifies that two PropertyPathSegment instances with different values are not equal. /// A task representing the asynchronous test operation. [Test] public async Task PropertyPathSegment_Equals_DifferentValues_ReturnsFalse() { - var a = new PropertyPathSegment("Name", "global::System.String", "global::TestApp.MyViewModel", true); - var b = new PropertyPathSegment("Age", "global::System.Int32", "global::TestApp.MyViewModel", false); + var a = new PropertyPathSegment("Name", StringTypeName, MyViewModelTypeName, true); + var b = new PropertyPathSegment("Age", Int32TypeName, MyViewModelTypeName, false); await Assert.That(a.Equals(b)).IsFalse(); } - /// - /// Verifies that PropertyPathSegment.Equals returns false when compared to null object. - /// + /// Verifies that PropertyPathSegment.Equals returns false when compared to null object. /// A task representing the asynchronous test operation. [Test] public async Task PropertyPathSegment_Equals_ObjectNull_ReturnsFalse() { - var a = new PropertyPathSegment("Name", "global::System.String", "global::TestApp.MyViewModel", true); + var a = new PropertyPathSegment("Name", StringTypeName, MyViewModelTypeName, true); await Assert.That(a.Equals(NullReference())).IsFalse(); } - /// - /// Verifies that PropertyPathSegment.Equals returns false when compared to a different type. - /// + /// Verifies that PropertyPathSegment.Equals returns false when compared to a different type. /// A task representing the asynchronous test operation. [Test] public async Task PropertyPathSegment_Equals_ObjectWrongType_ReturnsFalse() { - var a = new PropertyPathSegment("Name", "global::System.String", "global::TestApp.MyViewModel", true); + var a = new PropertyPathSegment("Name", StringTypeName, MyViewModelTypeName, true); - await Assert.That(a.Equals("string")).IsFalse(); + await Assert.That(a.Equals(StringName)).IsFalse(); } - /// - /// Verifies that two PropertyPathSegment instances with same values produce the same hash code. - /// + /// Verifies that two PropertyPathSegment instances with same values produce the same hash code. /// A task representing the asynchronous test operation. [Test] public async Task PropertyPathSegment_GetHashCode_SameValues_AreEqual() { - var a = new PropertyPathSegment("Name", "global::System.String", "global::TestApp.MyViewModel", true); - var b = new PropertyPathSegment("Name", "global::System.String", "global::TestApp.MyViewModel", true); + var a = new PropertyPathSegment("Name", StringTypeName, MyViewModelTypeName, true); + var b = new PropertyPathSegment("Name", StringTypeName, MyViewModelTypeName, true); await Assert.That(a.GetHashCode()).IsEqualTo(b.GetHashCode()); } - /// - /// Verifies that operator== returns true for PropertyPathSegment instances with same values. - /// + /// Verifies that operator== returns true for PropertyPathSegment instances with same values. /// A task representing the asynchronous test operation. [Test] public async Task PropertyPathSegment_OperatorEquals_SameValues_ReturnsTrue() { - var a = new PropertyPathSegment("Name", "global::System.String", "global::TestApp.MyViewModel", true); - var b = new PropertyPathSegment("Name", "global::System.String", "global::TestApp.MyViewModel", true); + var a = new PropertyPathSegment("Name", StringTypeName, MyViewModelTypeName, true); + var b = new PropertyPathSegment("Name", StringTypeName, MyViewModelTypeName, true); await Assert.That(a == b).IsTrue(); } - /// - /// Verifies that operator!= returns true for PropertyPathSegment instances with different values. - /// + /// Verifies that operator!= returns true for PropertyPathSegment instances with different values. /// A task representing the asynchronous test operation. [Test] public async Task PropertyPathSegment_OperatorNotEquals_DifferentValues_ReturnsTrue() { - var a = new PropertyPathSegment("Name", "global::System.String", "global::TestApp.MyViewModel", true); - var b = new PropertyPathSegment("Name", "global::System.String", "global::TestApp.OtherType", true); + var a = new PropertyPathSegment("Name", StringTypeName, MyViewModelTypeName, true); + var b = new PropertyPathSegment("Name", StringTypeName, "global::TestApp.OtherType", true); await Assert.That(a != b).IsTrue(); } - /// - /// Verifies that PropertyPathSegment.ToString contains the type name. - /// + /// Verifies that PropertyPathSegment.ToString contains the type name. /// A task representing the asynchronous test operation. [Test] public async Task PropertyPathSegment_ToString_ContainsTypeName() { - var a = new PropertyPathSegment("Name", "global::System.String", "global::TestApp.MyViewModel", true); + var a = new PropertyPathSegment("Name", StringTypeName, MyViewModelTypeName, true); await Assert.That(a.ToString()).Contains("PropertyPathSegment"); } @@ -571,10 +505,7 @@ public async Task PropertyPathSegment_ToString_ContainsTypeName() // ─────────────────────────────────────────────────────────────────────────── // ObservationCodeGenerator.TypeGroup // ─────────────────────────────────────────────────────────────────────────── - - /// - /// Verifies that two TypeGroup instances with identical values are equal. - /// + /// Verifies that two TypeGroup instances with identical values are equal. /// A task representing the asynchronous test operation. [Test] public async Task TypeGroup_Equals_SameValues_ReturnsTrue() @@ -588,9 +519,7 @@ public async Task TypeGroup_Equals_SameValues_ReturnsTrue() await Assert.That(a.Equals(b)).IsTrue(); } - /// - /// Verifies that two TypeGroup instances with different First values are not equal. - /// + /// Verifies that two TypeGroup instances with different First values are not equal. /// A task representing the asynchronous test operation. [Test] public async Task TypeGroup_Equals_DifferentValues_ReturnsFalse() @@ -604,9 +533,7 @@ public async Task TypeGroup_Equals_DifferentValues_ReturnsFalse() await Assert.That(a.Equals(b)).IsFalse(); } - /// - /// Verifies that TypeGroup.Equals returns false when compared to null object. - /// + /// Verifies that TypeGroup.Equals returns false when compared to null object. /// A task representing the asynchronous test operation. [Test] public async Task TypeGroup_Equals_ObjectNull_ReturnsFalse() @@ -617,9 +544,7 @@ public async Task TypeGroup_Equals_ObjectNull_ReturnsFalse() await Assert.That(a.Equals(NullReference())).IsFalse(); } - /// - /// Verifies that TypeGroup.Equals returns false when compared to a different type. - /// + /// Verifies that TypeGroup.Equals returns false when compared to a different type. /// A task representing the asynchronous test operation. [Test] public async Task TypeGroup_Equals_ObjectWrongType_ReturnsFalse() @@ -627,12 +552,10 @@ public async Task TypeGroup_Equals_ObjectWrongType_ReturnsFalse() var inv = ModelFactory.CreateInvocationInfo(); var a = new ObservationCodeGenerator.TypeGroup(inv, [inv]); - await Assert.That(a.Equals("string")).IsFalse(); + await Assert.That(a.Equals(StringName)).IsFalse(); } - /// - /// Verifies that two TypeGroup instances with same values produce the same hash code. - /// + /// Verifies that two TypeGroup instances with same values produce the same hash code. /// A task representing the asynchronous test operation. [Test] public async Task TypeGroup_GetHashCode_SameValues_AreEqual() @@ -646,9 +569,7 @@ public async Task TypeGroup_GetHashCode_SameValues_AreEqual() await Assert.That(a.GetHashCode()).IsEqualTo(b.GetHashCode()); } - /// - /// Verifies that operator== returns true for TypeGroup instances with same values. - /// + /// Verifies that operator== returns true for TypeGroup instances with same values. /// A task representing the asynchronous test operation. [Test] public async Task TypeGroup_OperatorEquals_SameValues_ReturnsTrue() @@ -662,9 +583,7 @@ public async Task TypeGroup_OperatorEquals_SameValues_ReturnsTrue() await Assert.That(a == b).IsTrue(); } - /// - /// Verifies that operator!= returns true for TypeGroup instances with different values. - /// + /// Verifies that operator!= returns true for TypeGroup instances with different values. /// A task representing the asynchronous test operation. [Test] public async Task TypeGroup_OperatorNotEquals_DifferentValues_ReturnsTrue() @@ -678,9 +597,7 @@ public async Task TypeGroup_OperatorNotEquals_DifferentValues_ReturnsTrue() await Assert.That(a != b).IsTrue(); } - /// - /// Verifies that TypeGroup.ToString contains the type name. - /// + /// Verifies that TypeGroup.ToString contains the type name. /// A task representing the asynchronous test operation. [Test] public async Task TypeGroup_ToString_ContainsTypeName() @@ -691,9 +608,7 @@ public async Task TypeGroup_ToString_ContainsTypeName() await Assert.That(a.ToString()).Contains("TypeGroup"); } - /// - /// Verifies that TypeGroup.SourceTypeFullName delegates to First.SourceTypeFullName. - /// + /// Verifies that TypeGroup.SourceTypeFullName delegates to First.SourceTypeFullName. /// A task representing the asynchronous test operation. [Test] public async Task TypeGroup_SourceTypeFullName_DelegatesToFirst() @@ -704,17 +619,15 @@ public async Task TypeGroup_SourceTypeFullName_DelegatesToFirst() await Assert.That(a.SourceTypeFullName).IsEqualTo("global::TestApp.SpecialViewModel"); } - /// - /// Verifies that TypeGroup.ReturnTypeFullName delegates to First.ReturnTypeFullName. - /// + /// Verifies that TypeGroup.ReturnTypeFullName delegates to First.ReturnTypeFullName. /// A task representing the asynchronous test operation. [Test] public async Task TypeGroup_ReturnTypeFullName_DelegatesToFirst() { - var inv = ModelFactory.CreateInvocationInfo(returnTypeFullName: "global::System.Int32"); + var inv = ModelFactory.CreateInvocationInfo(returnTypeFullName: Int32TypeName); var a = new ObservationCodeGenerator.TypeGroup(inv, [inv]); - await Assert.That(a.ReturnTypeFullName).IsEqualTo("global::System.Int32"); + await Assert.That(a.ReturnTypeFullName).IsEqualTo(Int32TypeName); } /// diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OBG.2STB_GEI#OneWayBindDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OBG.2STB_GEI#OneWayBindDispatch.g.verified.cs index 1567fe4..ea616ef 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OBG.2STB_GEI#OneWayBindDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OBG.2STB_GEI#OneWayBindDispatch.g.verified.cs @@ -16,28 +16,28 @@ internal static partial class __ReactiveUIGeneratedBindings public static global::ReactiveUI.Binding.IReactiveBinding OneWayBind( this global::SharedScenarios.OneWayBind.TwoSameTypeBindings.MyView view, global::SharedScenarios.OneWayBind.TwoSameTypeBindings.MyViewModel viewModel, - global::System.Linq.Expressions.Expression> vmProperty, + global::System.Linq.Expressions.Expression> viewModelProperty, global::System.Linq.Expressions.Expression> viewProperty, - [global::System.Runtime.CompilerServices.CallerArgumentExpression("vmProperty")] string vmPropertyExpression = "", + [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewModelProperty")] string viewModelPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewProperty")] string viewPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (vmPropertyExpression == "x => x.FirstName" + if (viewModelPropertyExpression == "x => x.FirstName" && viewPropertyExpression == "x => x.FirstNameText") { - return __OneWayBind_7FFFC92F35E57534(viewModel, view); + return __OneWayBind_7FFFC92F35E572C8(viewModel, view); } - else if (vmPropertyExpression == "x => x.LastName" + else if (viewModelPropertyExpression == "x => x.LastName" && viewPropertyExpression == "x => x.LastNameText") { - return __OneWayBind_7FFFC92F041A1BAB(viewModel, view); + return __OneWayBind_7FFFC92F041A193F(viewModel, view); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::ReactiveUI.Binding.IReactiveBinding __OneWayBind_7FFFC92F35E57534(global::SharedScenarios.OneWayBind.TwoSameTypeBindings.MyViewModel viewModel, global::SharedScenarios.OneWayBind.TwoSameTypeBindings.MyView view) + private static global::ReactiveUI.Binding.IReactiveBinding __OneWayBind_7FFFC92F35E572C8(global::SharedScenarios.OneWayBind.TwoSameTypeBindings.MyViewModel viewModel, global::SharedScenarios.OneWayBind.TwoSameTypeBindings.MyView view) { // OneWayBind: FirstName -> FirstNameText var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( @@ -58,7 +58,7 @@ internal static partial class __ReactiveUIGeneratedBindings sub); } - private static global::ReactiveUI.Binding.IReactiveBinding __OneWayBind_7FFFC92F041A1BAB(global::SharedScenarios.OneWayBind.TwoSameTypeBindings.MyViewModel viewModel, global::SharedScenarios.OneWayBind.TwoSameTypeBindings.MyView view) + private static global::ReactiveUI.Binding.IReactiveBinding __OneWayBind_7FFFC92F041A193F(global::SharedScenarios.OneWayBind.TwoSameTypeBindings.MyViewModel viewModel, global::SharedScenarios.OneWayBind.TwoSameTypeBindings.MyView view) { // OneWayBind: LastName -> LastNameText var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OBG.MB#OneWayBindDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OBG.MB#OneWayBindDispatch.g.verified.cs index 0f1a858..0132b17 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OBG.MB#OneWayBindDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OBG.MB#OneWayBindDispatch.g.verified.cs @@ -16,23 +16,23 @@ internal static partial class __ReactiveUIGeneratedBindings public static global::ReactiveUI.Binding.IReactiveBinding OneWayBind( this global::SharedScenarios.OneWayBind.MultipleBindings.MyView view, global::SharedScenarios.OneWayBind.MultipleBindings.MyViewModel viewModel, - global::System.Linq.Expressions.Expression> vmProperty, + global::System.Linq.Expressions.Expression> viewModelProperty, global::System.Linq.Expressions.Expression> viewProperty, - [global::System.Runtime.CompilerServices.CallerArgumentExpression("vmProperty")] string vmPropertyExpression = "", + [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewModelProperty")] string viewModelPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewProperty")] string viewPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (vmPropertyExpression == "x => x.Name" + if (viewModelPropertyExpression == "x => x.Name" && viewPropertyExpression == "x => x.NameText") { - return __OneWayBind_00002D734282E96E(viewModel, view); + return __OneWayBind_00002D734282E686(viewModel, view); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::ReactiveUI.Binding.IReactiveBinding __OneWayBind_00002D734282E96E(global::SharedScenarios.OneWayBind.MultipleBindings.MyViewModel viewModel, global::SharedScenarios.OneWayBind.MultipleBindings.MyView view) + private static global::ReactiveUI.Binding.IReactiveBinding __OneWayBind_00002D734282E686(global::SharedScenarios.OneWayBind.MultipleBindings.MyViewModel viewModel, global::SharedScenarios.OneWayBind.MultipleBindings.MyView view) { // OneWayBind: Name -> NameText var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( @@ -60,23 +60,23 @@ internal static partial class __ReactiveUIGeneratedBindings public static global::ReactiveUI.Binding.IReactiveBinding OneWayBind( this global::SharedScenarios.OneWayBind.MultipleBindings.MyView view, global::SharedScenarios.OneWayBind.MultipleBindings.MyViewModel viewModel, - global::System.Linq.Expressions.Expression> vmProperty, + global::System.Linq.Expressions.Expression> viewModelProperty, global::System.Linq.Expressions.Expression> viewProperty, - [global::System.Runtime.CompilerServices.CallerArgumentExpression("vmProperty")] string vmPropertyExpression = "", + [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewModelProperty")] string viewModelPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewProperty")] string viewPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (vmPropertyExpression == "x => x.Age" + if (viewModelPropertyExpression == "x => x.Age" && viewPropertyExpression == "x => x.AgeText") { - return __OneWayBind_00002D72E431FE2D(viewModel, view); + return __OneWayBind_00002D72E431FB45(viewModel, view); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::ReactiveUI.Binding.IReactiveBinding __OneWayBind_00002D72E431FE2D(global::SharedScenarios.OneWayBind.MultipleBindings.MyViewModel viewModel, global::SharedScenarios.OneWayBind.MultipleBindings.MyView view) + private static global::ReactiveUI.Binding.IReactiveBinding __OneWayBind_00002D72E431FB45(global::SharedScenarios.OneWayBind.MultipleBindings.MyViewModel viewModel, global::SharedScenarios.OneWayBind.MultipleBindings.MyView view) { // OneWayBind: Age -> AgeText var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OBG.SP_I2I#OneWayBindDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OBG.SP_I2I#OneWayBindDispatch.g.verified.cs index b129ad1..3372a22 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OBG.SP_I2I#OneWayBindDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OBG.SP_I2I#OneWayBindDispatch.g.verified.cs @@ -16,23 +16,23 @@ internal static partial class __ReactiveUIGeneratedBindings public static global::ReactiveUI.Binding.IReactiveBinding OneWayBind( this global::SharedScenarios.OneWayBind.SinglePropertyIntToInt.MyView view, global::SharedScenarios.OneWayBind.SinglePropertyIntToInt.MyViewModel viewModel, - global::System.Linq.Expressions.Expression> vmProperty, + global::System.Linq.Expressions.Expression> viewModelProperty, global::System.Linq.Expressions.Expression> viewProperty, - [global::System.Runtime.CompilerServices.CallerArgumentExpression("vmProperty")] string vmPropertyExpression = "", + [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewModelProperty")] string viewModelPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewProperty")] string viewPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (vmPropertyExpression == "x => x.Count" + if (viewModelPropertyExpression == "x => x.Count" && viewPropertyExpression == "x => x.CountValue") { - return __OneWayBind_0000344EFEEA6530(viewModel, view); + return __OneWayBind_0000344EFEEA6340(viewModel, view); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::ReactiveUI.Binding.IReactiveBinding __OneWayBind_0000344EFEEA6530(global::SharedScenarios.OneWayBind.SinglePropertyIntToInt.MyViewModel viewModel, global::SharedScenarios.OneWayBind.SinglePropertyIntToInt.MyView view) + private static global::ReactiveUI.Binding.IReactiveBinding __OneWayBind_0000344EFEEA6340(global::SharedScenarios.OneWayBind.SinglePropertyIntToInt.MyViewModel viewModel, global::SharedScenarios.OneWayBind.SinglePropertyIntToInt.MyView view) { // OneWayBind: Count -> CountValue var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OBG.SP_S2S#OneWayBindDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OBG.SP_S2S#OneWayBindDispatch.g.verified.cs index c2b1036..3ae1e3f 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OBG.SP_S2S#OneWayBindDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OBG.SP_S2S#OneWayBindDispatch.g.verified.cs @@ -16,23 +16,23 @@ internal static partial class __ReactiveUIGeneratedBindings public static global::ReactiveUI.Binding.IReactiveBinding OneWayBind( this global::SharedScenarios.OneWayBind.SinglePropertyStringToString.MyView view, global::SharedScenarios.OneWayBind.SinglePropertyStringToString.MyViewModel viewModel, - global::System.Linq.Expressions.Expression> vmProperty, + global::System.Linq.Expressions.Expression> viewModelProperty, global::System.Linq.Expressions.Expression> viewProperty, - [global::System.Runtime.CompilerServices.CallerArgumentExpression("vmProperty")] string vmPropertyExpression = "", + [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewModelProperty")] string viewModelPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewProperty")] string viewPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (vmPropertyExpression == "x => x.Name" + if (viewModelPropertyExpression == "x => x.Name" && viewPropertyExpression == "x => x.NameText") { - return __OneWayBind_7FFFC4A056D62C24(viewModel, view); + return __OneWayBind_7FFFC4A056D62A34(viewModel, view); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::ReactiveUI.Binding.IReactiveBinding __OneWayBind_7FFFC4A056D62C24(global::SharedScenarios.OneWayBind.SinglePropertyStringToString.MyViewModel viewModel, global::SharedScenarios.OneWayBind.SinglePropertyStringToString.MyView view) + private static global::ReactiveUI.Binding.IReactiveBinding __OneWayBind_7FFFC4A056D62A34(global::SharedScenarios.OneWayBind.SinglePropertyStringToString.MyViewModel viewModel, global::SharedScenarios.OneWayBind.SinglePropertyStringToString.MyView view) { // OneWayBind: Name -> NameText var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OBG.SP_S2S_CFP#OneWayBindDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OBG.SP_S2S_CFP#OneWayBindDispatch.g.verified.cs index 7199b88..bbf1218 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OBG.SP_S2S_CFP#OneWayBindDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OBG.SP_S2S_CFP#OneWayBindDispatch.g.verified.cs @@ -16,21 +16,21 @@ internal static partial class __ReactiveUIGeneratedBindings public static global::ReactiveUI.Binding.IReactiveBinding OneWayBind( this global::SharedScenarios.OneWayBind.SinglePropertyStringToString.MyView view, global::SharedScenarios.OneWayBind.SinglePropertyStringToString.MyViewModel viewModel, - global::System.Linq.Expressions.Expression> vmProperty, + global::System.Linq.Expressions.Expression> viewModelProperty, global::System.Linq.Expressions.Expression> viewProperty, [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (callerLineNumber == 90 + if (callerLineNumber == 74 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) { - return __OneWayBind_7FFFC4A056D62C24(viewModel, view); + return __OneWayBind_7FFFC4A056D62A34(viewModel, view); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::ReactiveUI.Binding.IReactiveBinding __OneWayBind_7FFFC4A056D62C24(global::SharedScenarios.OneWayBind.SinglePropertyStringToString.MyViewModel viewModel, global::SharedScenarios.OneWayBind.SinglePropertyStringToString.MyView view) + private static global::ReactiveUI.Binding.IReactiveBinding __OneWayBind_7FFFC4A056D62A34(global::SharedScenarios.OneWayBind.SinglePropertyStringToString.MyViewModel viewModel, global::SharedScenarios.OneWayBind.SinglePropertyStringToString.MyView view) { // OneWayBind: Name -> NameText var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OBG.SP_WS#OneWayBindDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OBG.SP_WS#OneWayBindDispatch.g.verified.cs index a60ecdf..9d1d6e1 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OBG.SP_WS#OneWayBindDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OBG.SP_WS#OneWayBindDispatch.g.verified.cs @@ -16,24 +16,24 @@ internal static partial class __ReactiveUIGeneratedBindings public static global::ReactiveUI.Binding.IReactiveBinding OneWayBind( this global::SharedScenarios.OneWayBind.SinglePropertyWithSelector.MyView view, global::SharedScenarios.OneWayBind.SinglePropertyWithSelector.MyViewModel viewModel, - global::System.Linq.Expressions.Expression> vmProperty, + global::System.Linq.Expressions.Expression> viewModelProperty, global::System.Linq.Expressions.Expression> viewProperty, global::System.Func selector, - [global::System.Runtime.CompilerServices.CallerArgumentExpression("vmProperty")] string vmPropertyExpression = "", + [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewModelProperty")] string viewModelPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewProperty")] string viewPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (vmPropertyExpression == "x => x.Count" + if (viewModelPropertyExpression == "x => x.Count" && viewPropertyExpression == "x => x.CountText") { - return __OneWayBind_0000321BF9FDED00(viewModel, view, selector); + return __OneWayBind_0000321BF9FDEB10(viewModel, view, selector); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::ReactiveUI.Binding.IReactiveBinding __OneWayBind_0000321BF9FDED00(global::SharedScenarios.OneWayBind.SinglePropertyWithSelector.MyViewModel viewModel, global::SharedScenarios.OneWayBind.SinglePropertyWithSelector.MyView view, global::System.Func selector) + private static global::ReactiveUI.Binding.IReactiveBinding __OneWayBind_0000321BF9FDEB10(global::SharedScenarios.OneWayBind.SinglePropertyWithSelector.MyViewModel viewModel, global::SharedScenarios.OneWayBind.SinglePropertyWithSelector.MyView view, global::System.Func selector) { // OneWayBind: Count -> CountText (with conversion) var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OBG.SP_WSSched#OneWayBindDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OBG.SP_WSSched#OneWayBindDispatch.g.verified.cs index 0eddb06..06b1f2a 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OBG.SP_WSSched#OneWayBindDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OBG.SP_WSSched#OneWayBindDispatch.g.verified.cs @@ -16,25 +16,25 @@ internal static partial class __ReactiveUIGeneratedBindings public static global::ReactiveUI.Binding.IReactiveBinding OneWayBind( this global::SharedScenarios.OneWayBind.SinglePropertyWithSelectorAndScheduler.MyView view, global::SharedScenarios.OneWayBind.SinglePropertyWithSelectorAndScheduler.MyViewModel viewModel, - global::System.Linq.Expressions.Expression> vmProperty, + global::System.Linq.Expressions.Expression> viewModelProperty, global::System.Linq.Expressions.Expression> viewProperty, global::System.Func selector, global::System.Reactive.Concurrency.IScheduler scheduler, - [global::System.Runtime.CompilerServices.CallerArgumentExpression("vmProperty")] string vmPropertyExpression = "", + [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewModelProperty")] string viewModelPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerArgumentExpression("viewProperty")] string viewPropertyExpression = "", [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (vmPropertyExpression == "x => x.Count" + if (viewModelPropertyExpression == "x => x.Count" && viewPropertyExpression == "x => x.CountText") { - return __OneWayBind_7FFFFAB8DECC397F(viewModel, view, selector, scheduler); + return __OneWayBind_7FFFFAB8DECC378F(viewModel, view, selector, scheduler); } throw new global::System.InvalidOperationException( "No generated binding found. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::ReactiveUI.Binding.IReactiveBinding __OneWayBind_7FFFFAB8DECC397F(global::SharedScenarios.OneWayBind.SinglePropertyWithSelectorAndScheduler.MyViewModel viewModel, global::SharedScenarios.OneWayBind.SinglePropertyWithSelectorAndScheduler.MyView view, global::System.Func selector, global::System.Reactive.Concurrency.IScheduler scheduler) + private static global::ReactiveUI.Binding.IReactiveBinding __OneWayBind_7FFFFAB8DECC378F(global::SharedScenarios.OneWayBind.SinglePropertyWithSelectorAndScheduler.MyViewModel viewModel, global::SharedScenarios.OneWayBind.SinglePropertyWithSelectorAndScheduler.MyView view, global::System.Func selector, global::System.Reactive.Concurrency.IScheduler scheduler) { // OneWayBind: Count -> CountText (with conversion) (with scheduler) var sourceObs = new global::ReactiveUI.Binding.Observables.PropertyObservable( diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OneWayBindGeneratorTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OneWayBindGeneratorTests.cs index 6914263..4fa5c0b 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OneWayBindGeneratorTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/OneWayBindGeneratorTests.cs @@ -7,14 +7,10 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests; -/// -/// Snapshot tests for OneWayBind (view-first one-way binding) invocation generation. -/// +/// Snapshot tests for OneWayBind (view-first one-way binding) invocation generation. public class OneWayBindGeneratorTests { - /// - /// Verifies OneWayBind with same-type string property binding. - /// + /// Verifies OneWayBind with same-type string property binding. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_StringToString() @@ -26,9 +22,7 @@ public async Task SingleProperty_StringToString() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies OneWayBind with multiple bindings on the same view/vm pair. - /// + /// Verifies OneWayBind with multiple bindings on the same view/vm pair. /// A task representing the asynchronous test operation. [Test] public async Task MultipleBindings() @@ -40,9 +34,7 @@ public async Task MultipleBindings() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies OneWayBind with int-to-int property binding. - /// + /// Verifies OneWayBind with int-to-int property binding. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_IntToInt() @@ -54,9 +46,7 @@ public async Task SingleProperty_IntToInt() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies OneWayBind with a selector (conversion) function from int to string. - /// + /// Verifies OneWayBind with a selector (conversion) function from int to string. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_WithSelector() @@ -68,9 +58,7 @@ public async Task SingleProperty_WithSelector() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies OneWayBind with a selector (conversion) function and scheduler. - /// + /// Verifies OneWayBind with a selector (conversion) function and scheduler. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_WithSelectorAndScheduler() diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/PlatformDetectionSnapshotTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/PlatformDetectionSnapshotTests.cs index 64b3bf6..41b3da7 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/PlatformDetectionSnapshotTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/PlatformDetectionSnapshotTests.cs @@ -13,9 +13,7 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests; /// public class PlatformDetectionSnapshotTests { - /// - /// Verifies detection of WPF DependencyObject. - /// + /// Verifies detection of WPF DependencyObject. /// A task representing the asynchronous test operation. [Test] public Task WpfDependencyObject_Detected() @@ -39,9 +37,7 @@ public class MyWpfControl : System.Windows.DependencyObject return TestHelper.TestPass(source, typeof(PlatformDetectionSnapshotTests)); } - /// - /// Verifies detection of WinForms Component. - /// + /// Verifies detection of WinForms Component. /// A task representing the asynchronous test operation. [Test] public Task WinFormsComponent_Detected() @@ -64,9 +60,7 @@ public class MyWinFormsControl : System.ComponentModel.Component return TestHelper.TestPass(source, typeof(PlatformDetectionSnapshotTests)); } - /// - /// Verifies detection of Android View. - /// + /// Verifies detection of Android View. /// A task representing the asynchronous test operation. [Test] public Task AndroidView_Detected() @@ -89,9 +83,7 @@ public class MyAndroidView : Android.Views.View return TestHelper.TestPass(source, typeof(PlatformDetectionSnapshotTests)); } - /// - /// Verifies detection of Apple NSObject (KVO). - /// + /// Verifies detection of Apple NSObject (KVO). /// A task representing the asynchronous test operation. [Test] public Task NSObject_Detected() diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Plugins/CommandBindingPluginTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Plugins/CommandBindingPluginTests.cs index 2be6576..bd647ab 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Plugins/CommandBindingPluginTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Plugins/CommandBindingPluginTests.cs @@ -9,18 +9,15 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests.Plugins; -/// -/// Unit tests for the and command binding plugins. -/// +/// Unit tests for the and command binding plugins. public class CommandBindingPluginTests { - /// - /// Verifies that GetBestPlugin returns CommandPropertyBindingPlugin when HasCommandProperty is true. - /// + /// Verifies that GetBestPlugin returns CommandPropertyBindingPlugin when HasCommandProperty is true. /// A task representing the asynchronous test operation. [Test] public async Task GetBestPlugin_HasCommandProperty_ReturnsCommandPropertyPlugin() { + const int Expected = 5; var inv = ModelFactory.CreateBindCommandInvocationInfo( resolvedEventName: "Click", hasCommandProperty: true, @@ -30,16 +27,15 @@ public async Task GetBestPlugin_HasCommandProperty_ReturnsCommandPropertyPlugin( await Assert.That(plugin).IsNotNull(); await Assert.That(plugin).IsTypeOf(); - await Assert.That(plugin!.Affinity).IsEqualTo(5); + await Assert.That(plugin!.Affinity).IsEqualTo(Expected); } - /// - /// Verifies that GetBestPlugin returns EventEnabledBindingPlugin when event and Enabled exist but no Command. - /// + /// Verifies that GetBestPlugin returns EventEnabledBindingPlugin when event and Enabled exist but no Command. /// A task representing the asynchronous test operation. [Test] public async Task GetBestPlugin_EventAndEnabled_ReturnsEventEnabledPlugin() { + const int Expected = 4; var inv = ModelFactory.CreateBindCommandInvocationInfo( resolvedEventName: "Click", hasCommandProperty: false, @@ -49,48 +45,38 @@ public async Task GetBestPlugin_EventAndEnabled_ReturnsEventEnabledPlugin() await Assert.That(plugin).IsNotNull(); await Assert.That(plugin).IsTypeOf(); - await Assert.That(plugin!.Affinity).IsEqualTo(4); + await Assert.That(plugin!.Affinity).IsEqualTo(Expected); } - /// - /// Verifies that GetBestPlugin returns DefaultEventBindingPlugin when event exists but no Command or Enabled. - /// + /// Verifies that GetBestPlugin returns DefaultEventBindingPlugin when event exists but no Command or Enabled. /// A task representing the asynchronous test operation. [Test] public async Task GetBestPlugin_EventOnly_ReturnsDefaultEventPlugin() { - var inv = ModelFactory.CreateBindCommandInvocationInfo( - resolvedEventName: "Click", - hasCommandProperty: false, - hasEnabledProperty: false); + const int Expected = 3; + var inv = ModelFactory.CreateBindCommandInvocationInfo(); var plugin = CommandBindingPluginRegistry.GetBestPlugin(inv); await Assert.That(plugin).IsNotNull(); await Assert.That(plugin).IsTypeOf(); - await Assert.That(plugin!.Affinity).IsEqualTo(3); + await Assert.That(plugin!.Affinity).IsEqualTo(Expected); } - /// - /// Verifies that GetBestPlugin returns null when no plugin can handle the invocation. - /// + /// Verifies that GetBestPlugin returns null when no plugin can handle the invocation. /// A task representing the asynchronous test operation. [Test] public async Task GetBestPlugin_NoEventNoCommand_ReturnsNull() { var inv = ModelFactory.CreateBindCommandInvocationInfo( - resolvedEventName: null, - hasCommandProperty: false, - hasEnabledProperty: false); + resolvedEventName: null); var plugin = CommandBindingPluginRegistry.GetBestPlugin(inv); await Assert.That(plugin).IsNull(); } - /// - /// Verifies CommandPropertyBindingPlugin.RequiresCustomBinderFallback is false. - /// + /// Verifies CommandPropertyBindingPlugin.RequiresCustomBinderFallback is false. /// A task representing the asynchronous test operation. [Test] public async Task CommandPropertyPlugin_RequiresCustomBinderFallback_IsFalse() @@ -99,9 +85,7 @@ public async Task CommandPropertyPlugin_RequiresCustomBinderFallback_IsFalse() await Assert.That(plugin.RequiresCustomBinderFallback).IsFalse(); } - /// - /// Verifies EventEnabledBindingPlugin.RequiresCustomBinderFallback is true. - /// + /// Verifies EventEnabledBindingPlugin.RequiresCustomBinderFallback is true. /// A task representing the asynchronous test operation. [Test] public async Task EventEnabledPlugin_RequiresCustomBinderFallback_IsTrue() @@ -110,9 +94,7 @@ public async Task EventEnabledPlugin_RequiresCustomBinderFallback_IsTrue() await Assert.That(plugin.RequiresCustomBinderFallback).IsTrue(); } - /// - /// Verifies DefaultEventBindingPlugin.RequiresCustomBinderFallback is true. - /// + /// Verifies DefaultEventBindingPlugin.RequiresCustomBinderFallback is true. /// A task representing the asynchronous test operation. [Test] public async Task DefaultEventPlugin_RequiresCustomBinderFallback_IsTrue() diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Plugins/ObservationPluginTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Plugins/ObservationPluginTests.cs index 4917388..713700c 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Plugins/ObservationPluginTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/Plugins/ObservationPluginTests.cs @@ -10,171 +10,211 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests.Plugins; -/// -/// Unit tests for all observation plugins, covering emit methods not exercised by snapshot tests. -/// +/// Unit tests for all observation plugins, covering emit methods not exercised by snapshot tests. public class ObservationPluginTests { - // ========== WpfObservationPlugin ========== + /// The EventObservable name these tests generate against. + private const string EventObservableName = "EventObservable"; + + /// The false) fragment these tests expect in the generated source. + private const string FalseFragment = "false)"; + + /// The fully qualified name of the Address type used by these tests. + private const string AddressTypeName = "global::TestApp.Address"; + + /// The fully qualified name of the Inner type used by these tests. + private const string InnerTypeName = "global::TestApp.Inner"; + + /// The fully qualified name of the MyAndroidView type used by these tests. + private const string MyAndroidViewTypeName = "global::TestApp.MyAndroidView"; + + /// The fully qualified name of the MyControl type used by these tests. + private const string MyControlTypeName = "global::TestApp.MyControl"; + + /// The fully qualified name of the MyTextBox type used by these tests. + private const string MyTextBoxTypeName = "global::TestApp.MyTextBox"; + + /// The fully qualified name of the MyView type used by these tests. + private const string MyViewTypeName = "global::TestApp.MyView"; + + /// The __KVOObservable local the generated code is expected to emit. + private const string KVOObservableLocal = "__KVOObservable"; + + /// The __obs0 local the generated code is expected to emit. + private const string Obs0Local = "__obs0"; + + /// The __obs1 local the generated code is expected to emit. + private const string Obs1Local = "__obs1"; + + /// The ReturnObservable name these tests generate against. + private const string ReturnObservableName = "ReturnObservable"; + + /// The source name these tests generate against. + private const string SourceName = "source"; + + /// The sourceObs name these tests generate against. + private const string SourceObsName = "sourceObs"; + + /// The string name these tests generate against. + private const string StringName = "string"; + + /// The Switch name these tests generate against. + private const string SwitchName = "Switch"; - /// - /// Verifies WPF plugin shallow observation emits EventObservable with DependencyPropertyDescriptor. - /// + /// The TextChanged name these tests generate against. + private const string TextChangedName = "TextChanged"; + + /// The true) fragment these tests expect in the generated source. + private const string TrueFragment = "true)"; + + /// The var __obs0 local the generated code is expected to emit. + private const string Obs0Declaration = "var __obs0"; + + /// The var sourceObs local the generated code is expected to emit. + private const string SourceObsDeclaration = "var sourceObs"; + + /// The __WinUIDPObservable local the generated code is expected to emit. + private const string WinUIDPObservableLocal = "__WinUIDPObservable"; + + // ========== WpfObservationPlugin ========== + /// Verifies WPF plugin shallow observation emits EventObservable with DependencyPropertyDescriptor. /// A task representing the asynchronous test operation. [Test] public async Task WpfPlugin_EmitShallowObservation_AfterChange_EmitsEventObservable() { var plugin = new WpfObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitShallowObservation(sb, "obj", segment, "global::TestApp.MyControl", false, true); + plugin.EmitShallowObservation(sb, "obj", segment, MyControlTypeName, false, true); var result = sb.ToString(); - await Assert.That(result).Contains("EventObservable"); + await Assert.That(result).Contains(EventObservableName); await Assert.That(result).Contains("DependencyPropertyDescriptor"); await Assert.That(result).Contains("TextProperty"); } - /// - /// Verifies WPF plugin shallow observation before-change emits ReturnObservable. - /// + /// Verifies WPF plugin shallow observation before-change emits ReturnObservable. /// A task representing the asynchronous test operation. [Test] public async Task WpfPlugin_EmitShallowObservation_BeforeChange_EmitsReturnObservable() { var plugin = new WpfObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitShallowObservation(sb, "obj", segment, "global::TestApp.MyControl", true, true); + plugin.EmitShallowObservation(sb, "obj", segment, MyControlTypeName, true, true); - await Assert.That(sb.ToString()).Contains("ReturnObservable"); + await Assert.That(sb.ToString()).Contains(ReturnObservableName); } - /// - /// Verifies WPF plugin shallow observation variable emits EventObservable. - /// + /// Verifies WPF plugin shallow observation variable emits EventObservable. /// A task representing the asynchronous test operation. [Test] public async Task WpfPlugin_EmitShallowObservationVariable_AfterChange_EmitsEventObservable() { var plugin = new WpfObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitShallowObservationVariable(sb, "obj", segment, "global::TestApp.MyControl", false, "__obs0"); + plugin.EmitShallowObservationVariable(sb, "obj", segment, MyControlTypeName, false, Obs0Local); var result = sb.ToString(); - await Assert.That(result).Contains("var __obs0"); - await Assert.That(result).Contains("EventObservable"); + await Assert.That(result).Contains(Obs0Declaration); + await Assert.That(result).Contains(EventObservableName); } - /// - /// Verifies WPF plugin shallow observation variable before-change emits ReturnObservable. - /// + /// Verifies WPF plugin shallow observation variable before-change emits ReturnObservable. /// A task representing the asynchronous test operation. [Test] public async Task WpfPlugin_EmitShallowObservationVariable_BeforeChange_EmitsReturnObservable() { var plugin = new WpfObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitShallowObservationVariable(sb, "obj", segment, "global::TestApp.MyControl", true, "__obs0"); + plugin.EmitShallowObservationVariable(sb, "obj", segment, MyControlTypeName, true, Obs0Local); - await Assert.That(sb.ToString()).Contains("ReturnObservable"); + await Assert.That(sb.ToString()).Contains(ReturnObservableName); } - /// - /// Verifies WPF plugin deep chain root segment after-change emits EventObservable. - /// + /// Verifies WPF plugin deep chain root segment after-change emits EventObservable. /// A task representing the asynchronous test operation. [Test] public async Task WpfPlugin_EmitDeepChainRootSegment_AfterChange_EmitsEventObservable() { var plugin = new WpfObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitDeepChainRootSegment(sb, "obj", segment, "global::TestApp.MyControl", false, "__obs0"); + plugin.EmitDeepChainRootSegment(sb, "obj", segment, MyControlTypeName, false, Obs0Local); var result = sb.ToString(); - await Assert.That(result).Contains("EventObservable"); - await Assert.That(result).Contains("var __obs0"); + await Assert.That(result).Contains(EventObservableName); + await Assert.That(result).Contains(Obs0Declaration); } - /// - /// Verifies WPF plugin deep chain root segment before-change emits ReturnObservable. - /// + /// Verifies WPF plugin deep chain root segment before-change emits ReturnObservable. /// A task representing the asynchronous test operation. [Test] public async Task WpfPlugin_EmitDeepChainRootSegment_BeforeChange_EmitsReturnObservable() { var plugin = new WpfObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitDeepChainRootSegment(sb, "obj", segment, "global::TestApp.MyControl", true, "__obs0"); + plugin.EmitDeepChainRootSegment(sb, "obj", segment, MyControlTypeName, true, Obs0Local); - await Assert.That(sb.ToString()).Contains("ReturnObservable"); + await Assert.That(sb.ToString()).Contains(ReturnObservableName); } - /// - /// Verifies WPF plugin deep chain inner segment after-change emits EventObservable with Switch. - /// + /// Verifies WPF plugin deep chain inner segment after-change emits EventObservable with Switch. /// A task representing the asynchronous test operation. [Test] public async Task WpfPlugin_EmitDeepChainInnerSegment_AfterChange_EmitsEventObservable() { var plugin = new WpfObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("City", "string", "global::TestApp.Address"); + var segment = ModelFactory.CreatePropertyPathSegment("City", StringName, AddressTypeName); - plugin.EmitDeepChainInnerSegment(sb, "__obs0", "__obs1", "__p1", segment, false); + plugin.EmitDeepChainInnerSegment(sb, Obs0Local, Obs1Local, "__p1", segment, false); var result = sb.ToString(); - await Assert.That(result).Contains("EventObservable"); - await Assert.That(result).Contains("Switch"); + await Assert.That(result).Contains(EventObservableName); + await Assert.That(result).Contains(SwitchName); } - /// - /// Verifies WPF plugin deep chain inner segment before-change emits ReturnObservable. - /// + /// Verifies WPF plugin deep chain inner segment before-change emits ReturnObservable. /// A task representing the asynchronous test operation. [Test] public async Task WpfPlugin_EmitDeepChainInnerSegment_BeforeChange_EmitsReturnObservable() { var plugin = new WpfObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("City", "string", "global::TestApp.Address"); + var segment = ModelFactory.CreatePropertyPathSegment("City", StringName, AddressTypeName); - plugin.EmitDeepChainInnerSegment(sb, "__obs0", "__obs1", "__p1", segment, true); + plugin.EmitDeepChainInnerSegment(sb, Obs0Local, Obs1Local, "__p1", segment, true); - await Assert.That(sb.ToString()).Contains("ReturnObservable"); + await Assert.That(sb.ToString()).Contains(ReturnObservableName); } - /// - /// Verifies WPF plugin inline observation variable emits EventObservable. - /// + /// Verifies WPF plugin inline observation variable emits EventObservable. /// A task representing the asynchronous test operation. [Test] public async Task WpfPlugin_EmitInlineObservationVariable_EmitsEventObservable() { var plugin = new WpfObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitInlineObservationVariable(sb, "source", segment, "global::TestApp.MyControl", "sourceObs"); + plugin.EmitInlineObservationVariable(sb, SourceName, segment, MyControlTypeName, SourceObsName); var result = sb.ToString(); - await Assert.That(result).Contains("EventObservable"); - await Assert.That(result).Contains("var sourceObs"); + await Assert.That(result).Contains(EventObservableName); + await Assert.That(result).Contains(SourceObsDeclaration); } - /// - /// Verifies WPF plugin EmitHelperClasses is a no-op. - /// + /// Verifies WPF plugin EmitHelperClasses is a no-op. /// A task representing the asynchronous test operation. [Test] public async Task WpfPlugin_EmitHelperClasses_IsNoOp() @@ -187,24 +227,21 @@ public async Task WpfPlugin_EmitHelperClasses_IsNoOp() await Assert.That(sb.Length).IsEqualTo(0); } - /// - /// Verifies WPF plugin properties. - /// + /// Verifies WPF plugin properties. /// A task representing the asynchronous test operation. [Test] public async Task WpfPlugin_Properties_AreCorrect() { + const int ExpectedPluginAffinity = 4; var plugin = new WpfObservationPlugin(); - await Assert.That(plugin.Affinity).IsEqualTo(4); + await Assert.That(plugin.Affinity).IsEqualTo(ExpectedPluginAffinity); await Assert.That(plugin.ObservationKind).IsEqualTo("WpfDP"); await Assert.That(plugin.SupportsBeforeChanged).IsFalse(); await Assert.That(plugin.RequiresHelperClasses).IsFalse(); } - /// - /// Verifies WPF plugin matches WPF DependencyObject types. - /// + /// Verifies WPF plugin matches WPF DependencyObject types. /// A task representing the asynchronous test operation. [Test] public async Task WpfPlugin_IsAMatch_WpfDependencyObject() @@ -216,146 +253,127 @@ public async Task WpfPlugin_IsAMatch_WpfDependencyObject() } // ========== WinFormsObservationPlugin ========== - - /// - /// Verifies WinForms plugin shallow observation variable after-change emits EventObservable. - /// + /// Verifies WinForms plugin shallow observation variable after-change emits EventObservable. /// A task representing the asynchronous test operation. [Test] public async Task WinFormsPlugin_EmitShallowObservationVariable_AfterChange_EmitsEventObservable() { var plugin = new WinFormsObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitShallowObservationVariable(sb, "obj", segment, "global::TestApp.MyTextBox", false, "__obs0"); + plugin.EmitShallowObservationVariable(sb, "obj", segment, MyTextBoxTypeName, false, Obs0Local); var result = sb.ToString(); - await Assert.That(result).Contains("EventObservable"); - await Assert.That(result).Contains("TextChanged"); + await Assert.That(result).Contains(EventObservableName); + await Assert.That(result).Contains(TextChangedName); } - /// - /// Verifies WinForms plugin shallow observation variable before-change emits ReturnObservable. - /// + /// Verifies WinForms plugin shallow observation variable before-change emits ReturnObservable. /// A task representing the asynchronous test operation. [Test] public async Task WinFormsPlugin_EmitShallowObservationVariable_BeforeChange_EmitsReturnObservable() { var plugin = new WinFormsObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitShallowObservationVariable(sb, "obj", segment, "global::TestApp.MyTextBox", true, "__obs0"); + plugin.EmitShallowObservationVariable(sb, "obj", segment, MyTextBoxTypeName, true, Obs0Local); - await Assert.That(sb.ToString()).Contains("ReturnObservable"); + await Assert.That(sb.ToString()).Contains(ReturnObservableName); } - /// - /// Verifies WinForms plugin shallow observation before-change emits ReturnObservable. - /// + /// Verifies WinForms plugin shallow observation before-change emits ReturnObservable. /// A task representing the asynchronous test operation. [Test] public async Task WinFormsPlugin_EmitShallowObservation_BeforeChange_EmitsReturnObservable() { var plugin = new WinFormsObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitShallowObservation(sb, "obj", segment, "global::TestApp.MyTextBox", true, true); + plugin.EmitShallowObservation(sb, "obj", segment, MyTextBoxTypeName, true, true); - await Assert.That(sb.ToString()).Contains("ReturnObservable"); + await Assert.That(sb.ToString()).Contains(ReturnObservableName); } - /// - /// Verifies WinForms plugin deep chain root segment after-change emits EventObservable. - /// + /// Verifies WinForms plugin deep chain root segment after-change emits EventObservable. /// A task representing the asynchronous test operation. [Test] public async Task WinFormsPlugin_EmitDeepChainRootSegment_AfterChange_EmitsEventObservable() { var plugin = new WinFormsObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitDeepChainRootSegment(sb, "obj", segment, "global::TestApp.MyTextBox", false, "__obs0"); + plugin.EmitDeepChainRootSegment(sb, "obj", segment, MyTextBoxTypeName, false, Obs0Local); var result = sb.ToString(); - await Assert.That(result).Contains("EventObservable"); - await Assert.That(result).Contains("TextChanged"); + await Assert.That(result).Contains(EventObservableName); + await Assert.That(result).Contains(TextChangedName); } - /// - /// Verifies WinForms plugin deep chain root segment before-change emits ReturnObservable. - /// + /// Verifies WinForms plugin deep chain root segment before-change emits ReturnObservable. /// A task representing the asynchronous test operation. [Test] public async Task WinFormsPlugin_EmitDeepChainRootSegment_BeforeChange_EmitsReturnObservable() { var plugin = new WinFormsObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitDeepChainRootSegment(sb, "obj", segment, "global::TestApp.MyTextBox", true, "__obs0"); + plugin.EmitDeepChainRootSegment(sb, "obj", segment, MyTextBoxTypeName, true, Obs0Local); - await Assert.That(sb.ToString()).Contains("ReturnObservable"); + await Assert.That(sb.ToString()).Contains(ReturnObservableName); } - /// - /// Verifies WinForms plugin deep chain inner segment after-change emits EventObservable. - /// + /// Verifies WinForms plugin deep chain inner segment after-change emits EventObservable. /// A task representing the asynchronous test operation. [Test] public async Task WinFormsPlugin_EmitDeepChainInnerSegment_AfterChange_EmitsEventObservable() { var plugin = new WinFormsObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string", "global::TestApp.Inner"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName, InnerTypeName); - plugin.EmitDeepChainInnerSegment(sb, "__obs0", "__obs1", "__p1", segment, false); + plugin.EmitDeepChainInnerSegment(sb, Obs0Local, Obs1Local, "__p1", segment, false); var result = sb.ToString(); - await Assert.That(result).Contains("EventObservable"); - await Assert.That(result).Contains("Switch"); + await Assert.That(result).Contains(EventObservableName); + await Assert.That(result).Contains(SwitchName); } - /// - /// Verifies WinForms plugin deep chain inner segment before-change emits ReturnObservable. - /// + /// Verifies WinForms plugin deep chain inner segment before-change emits ReturnObservable. /// A task representing the asynchronous test operation. [Test] public async Task WinFormsPlugin_EmitDeepChainInnerSegment_BeforeChange_EmitsReturnObservable() { var plugin = new WinFormsObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string", "global::TestApp.Inner"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName, InnerTypeName); - plugin.EmitDeepChainInnerSegment(sb, "__obs0", "__obs1", "__p1", segment, true); + plugin.EmitDeepChainInnerSegment(sb, Obs0Local, Obs1Local, "__p1", segment, true); - await Assert.That(sb.ToString()).Contains("ReturnObservable"); + await Assert.That(sb.ToString()).Contains(ReturnObservableName); } - /// - /// Verifies WinForms plugin inline observation variable emits EventObservable. - /// + /// Verifies WinForms plugin inline observation variable emits EventObservable. /// A task representing the asynchronous test operation. [Test] public async Task WinFormsPlugin_EmitInlineObservationVariable_EmitsEventObservable() { var plugin = new WinFormsObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitInlineObservationVariable(sb, "source", segment, "global::TestApp.MyTextBox", "sourceObs"); + plugin.EmitInlineObservationVariable(sb, SourceName, segment, MyTextBoxTypeName, SourceObsName); var result = sb.ToString(); - await Assert.That(result).Contains("EventObservable"); - await Assert.That(result).Contains("TextChanged"); + await Assert.That(result).Contains(EventObservableName); + await Assert.That(result).Contains(TextChangedName); } - /// - /// Verifies WinForms plugin EmitHelperClasses is a no-op. - /// + /// Verifies WinForms plugin EmitHelperClasses is a no-op. /// A task representing the asynchronous test operation. [Test] public async Task WinFormsPlugin_EmitHelperClasses_IsNoOp() @@ -369,144 +387,125 @@ public async Task WinFormsPlugin_EmitHelperClasses_IsNoOp() } // ========== WinUIObservationPlugin ========== - - /// - /// Verifies WinUI plugin shallow observation before-change emits ReturnObservable. - /// + /// Verifies WinUI plugin shallow observation before-change emits ReturnObservable. /// A task representing the asynchronous test operation. [Test] public async Task WinUIPlugin_EmitShallowObservation_BeforeChange_EmitsReturnObservable() { var plugin = new WinUIObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitShallowObservation(sb, "obj", segment, "global::TestApp.MyControl", true, true); + plugin.EmitShallowObservation(sb, "obj", segment, MyControlTypeName, true, true); - await Assert.That(sb.ToString()).Contains("ReturnObservable"); + await Assert.That(sb.ToString()).Contains(ReturnObservableName); } - /// - /// Verifies WinUI plugin shallow observation variable after-change emits WinUIDPObservable. - /// + /// Verifies WinUI plugin shallow observation variable after-change emits WinUIDPObservable. /// A task representing the asynchronous test operation. [Test] public async Task WinUIPlugin_EmitShallowObservationVariable_AfterChange_EmitsWinUIDPObservable() { var plugin = new WinUIObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitShallowObservationVariable(sb, "obj", segment, "global::TestApp.MyControl", false, "__obs0"); + plugin.EmitShallowObservationVariable(sb, "obj", segment, MyControlTypeName, false, Obs0Local); var result = sb.ToString(); - await Assert.That(result).Contains("__WinUIDPObservable"); - await Assert.That(result).Contains("var __obs0"); + await Assert.That(result).Contains(WinUIDPObservableLocal); + await Assert.That(result).Contains(Obs0Declaration); } - /// - /// Verifies WinUI plugin shallow observation variable before-change emits ReturnObservable. - /// + /// Verifies WinUI plugin shallow observation variable before-change emits ReturnObservable. /// A task representing the asynchronous test operation. [Test] public async Task WinUIPlugin_EmitShallowObservationVariable_BeforeChange_EmitsReturnObservable() { var plugin = new WinUIObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitShallowObservationVariable(sb, "obj", segment, "global::TestApp.MyControl", true, "__obs0"); + plugin.EmitShallowObservationVariable(sb, "obj", segment, MyControlTypeName, true, Obs0Local); - await Assert.That(sb.ToString()).Contains("ReturnObservable"); + await Assert.That(sb.ToString()).Contains(ReturnObservableName); } - /// - /// Verifies WinUI plugin deep chain root segment after-change emits WinUIDPObservable. - /// + /// Verifies WinUI plugin deep chain root segment after-change emits WinUIDPObservable. /// A task representing the asynchronous test operation. [Test] public async Task WinUIPlugin_EmitDeepChainRootSegment_AfterChange_EmitsWinUIDPObservable() { var plugin = new WinUIObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitDeepChainRootSegment(sb, "obj", segment, "global::TestApp.MyControl", false, "__obs0"); + plugin.EmitDeepChainRootSegment(sb, "obj", segment, MyControlTypeName, false, Obs0Local); - await Assert.That(sb.ToString()).Contains("__WinUIDPObservable"); + await Assert.That(sb.ToString()).Contains(WinUIDPObservableLocal); } - /// - /// Verifies WinUI plugin deep chain root segment before-change emits ReturnObservable. - /// + /// Verifies WinUI plugin deep chain root segment before-change emits ReturnObservable. /// A task representing the asynchronous test operation. [Test] public async Task WinUIPlugin_EmitDeepChainRootSegment_BeforeChange_EmitsReturnObservable() { var plugin = new WinUIObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitDeepChainRootSegment(sb, "obj", segment, "global::TestApp.MyControl", true, "__obs0"); + plugin.EmitDeepChainRootSegment(sb, "obj", segment, MyControlTypeName, true, Obs0Local); - await Assert.That(sb.ToString()).Contains("ReturnObservable"); + await Assert.That(sb.ToString()).Contains(ReturnObservableName); } - /// - /// Verifies WinUI plugin deep chain inner segment after-change emits WinUIDPObservable. - /// + /// Verifies WinUI plugin deep chain inner segment after-change emits WinUIDPObservable. /// A task representing the asynchronous test operation. [Test] public async Task WinUIPlugin_EmitDeepChainInnerSegment_AfterChange_EmitsWinUIDPObservable() { var plugin = new WinUIObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string", "global::TestApp.Inner"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName, InnerTypeName); - plugin.EmitDeepChainInnerSegment(sb, "__obs0", "__obs1", "__p1", segment, false); + plugin.EmitDeepChainInnerSegment(sb, Obs0Local, Obs1Local, "__p1", segment, false); var result = sb.ToString(); - await Assert.That(result).Contains("__WinUIDPObservable"); - await Assert.That(result).Contains("Switch"); + await Assert.That(result).Contains(WinUIDPObservableLocal); + await Assert.That(result).Contains(SwitchName); } - /// - /// Verifies WinUI plugin deep chain inner segment before-change emits ReturnObservable. - /// + /// Verifies WinUI plugin deep chain inner segment before-change emits ReturnObservable. /// A task representing the asynchronous test operation. [Test] public async Task WinUIPlugin_EmitDeepChainInnerSegment_BeforeChange_EmitsReturnObservable() { var plugin = new WinUIObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string", "global::TestApp.Inner"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName, InnerTypeName); - plugin.EmitDeepChainInnerSegment(sb, "__obs0", "__obs1", "__p1", segment, true); + plugin.EmitDeepChainInnerSegment(sb, Obs0Local, Obs1Local, "__p1", segment, true); - await Assert.That(sb.ToString()).Contains("ReturnObservable"); + await Assert.That(sb.ToString()).Contains(ReturnObservableName); } - /// - /// Verifies WinUI plugin inline observation variable emits WinUIDPObservable. - /// + /// Verifies WinUI plugin inline observation variable emits WinUIDPObservable. /// A task representing the asynchronous test operation. [Test] public async Task WinUIPlugin_EmitInlineObservationVariable_EmitsWinUIDPObservable() { var plugin = new WinUIObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitInlineObservationVariable(sb, "source", segment, "global::TestApp.MyControl", "sourceObs"); + plugin.EmitInlineObservationVariable(sb, SourceName, segment, MyControlTypeName, SourceObsName); var result = sb.ToString(); - await Assert.That(result).Contains("__WinUIDPObservable"); - await Assert.That(result).Contains("var sourceObs"); + await Assert.That(result).Contains(WinUIDPObservableLocal); + await Assert.That(result).Contains(SourceObsDeclaration); } - /// - /// Verifies WinUI plugin emits helper classes with __WinUIDPObservable. - /// + /// Verifies WinUI plugin emits helper classes with __WinUIDPObservable. /// A task representing the asynchronous test operation. [Test] public async Task WinUIPlugin_EmitHelperClasses_EmitsWinUIDPObservable() @@ -517,141 +516,124 @@ public async Task WinUIPlugin_EmitHelperClasses_EmitsWinUIDPObservable() plugin.EmitHelperClasses(sb); var result = sb.ToString(); - await Assert.That(result).Contains("__WinUIDPObservable"); + await Assert.That(result).Contains(WinUIDPObservableLocal); await Assert.That(result).Contains("RegisterPropertyChangedCallback"); } // ========== KVOObservationPlugin ========== - - /// - /// Verifies KVO plugin shallow observation variable after-change emits KVOObservable. - /// + /// Verifies KVO plugin shallow observation variable after-change emits KVOObservable. /// A task representing the asynchronous test operation. [Test] public async Task KVOPlugin_EmitShallowObservationVariable_AfterChange_EmitsKVOObservable() { var plugin = new KVOObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitShallowObservationVariable(sb, "obj", segment, "global::TestApp.MyView", false, "__obs0"); + plugin.EmitShallowObservationVariable(sb, "obj", segment, MyViewTypeName, false, Obs0Local); var result = sb.ToString(); - await Assert.That(result).Contains("__KVOObservable"); + await Assert.That(result).Contains(KVOObservableLocal); await Assert.That(result).Contains("\"text\""); } - /// - /// Verifies KVO plugin shallow observation variable before-change emits KVOObservable with beforeChange true. - /// + /// Verifies KVO plugin shallow observation variable before-change emits KVOObservable with beforeChange true. /// A task representing the asynchronous test operation. [Test] public async Task KVOPlugin_EmitShallowObservationVariable_BeforeChange_EmitsKVOObservable() { var plugin = new KVOObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitShallowObservationVariable(sb, "obj", segment, "global::TestApp.MyView", true, "__obs0"); + plugin.EmitShallowObservationVariable(sb, "obj", segment, MyViewTypeName, true, Obs0Local); var result = sb.ToString(); - await Assert.That(result).Contains("__KVOObservable"); - await Assert.That(result).Contains("true)"); + await Assert.That(result).Contains(KVOObservableLocal); + await Assert.That(result).Contains(TrueFragment); } - /// - /// Verifies KVO plugin deep chain root segment emits KVOObservable. - /// + /// Verifies KVO plugin deep chain root segment emits KVOObservable. /// A task representing the asynchronous test operation. [Test] public async Task KVOPlugin_EmitDeepChainRootSegment_AfterChange_EmitsKVOObservable() { var plugin = new KVOObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitDeepChainRootSegment(sb, "obj", segment, "global::TestApp.MyView", false, "__obs0"); + plugin.EmitDeepChainRootSegment(sb, "obj", segment, MyViewTypeName, false, Obs0Local); var result = sb.ToString(); - await Assert.That(result).Contains("__KVOObservable"); + await Assert.That(result).Contains(KVOObservableLocal); await Assert.That(result).Contains("\"text\""); } - /// - /// Verifies KVO plugin deep chain root segment before-change emits KVOObservable. - /// + /// Verifies KVO plugin deep chain root segment before-change emits KVOObservable. /// A task representing the asynchronous test operation. [Test] public async Task KVOPlugin_EmitDeepChainRootSegment_BeforeChange_EmitsKVOObservable() { var plugin = new KVOObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitDeepChainRootSegment(sb, "obj", segment, "global::TestApp.MyView", true, "__obs0"); + plugin.EmitDeepChainRootSegment(sb, "obj", segment, MyViewTypeName, true, Obs0Local); var result = sb.ToString(); - await Assert.That(result).Contains("__KVOObservable"); - await Assert.That(result).Contains("true)"); + await Assert.That(result).Contains(KVOObservableLocal); + await Assert.That(result).Contains(TrueFragment); } - /// - /// Verifies KVO plugin deep chain inner segment emits KVOObservable with Switch. - /// + /// Verifies KVO plugin deep chain inner segment emits KVOObservable with Switch. /// A task representing the asynchronous test operation. [Test] public async Task KVOPlugin_EmitDeepChainInnerSegment_AfterChange_EmitsKVOObservable() { var plugin = new KVOObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("City", "string", "global::TestApp.Address"); + var segment = ModelFactory.CreatePropertyPathSegment("City", StringName, AddressTypeName); - plugin.EmitDeepChainInnerSegment(sb, "__obs0", "__obs1", "__p1", segment, false); + plugin.EmitDeepChainInnerSegment(sb, Obs0Local, Obs1Local, "__p1", segment, false); var result = sb.ToString(); - await Assert.That(result).Contains("__KVOObservable"); - await Assert.That(result).Contains("Switch"); + await Assert.That(result).Contains(KVOObservableLocal); + await Assert.That(result).Contains(SwitchName); } - /// - /// Verifies KVO plugin deep chain inner segment before-change emits KVOObservable. - /// + /// Verifies KVO plugin deep chain inner segment before-change emits KVOObservable. /// A task representing the asynchronous test operation. [Test] public async Task KVOPlugin_EmitDeepChainInnerSegment_BeforeChange_EmitsKVOObservable() { var plugin = new KVOObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("City", "string", "global::TestApp.Address"); + var segment = ModelFactory.CreatePropertyPathSegment("City", StringName, AddressTypeName); - plugin.EmitDeepChainInnerSegment(sb, "__obs0", "__obs1", "__p1", segment, true); + plugin.EmitDeepChainInnerSegment(sb, Obs0Local, Obs1Local, "__p1", segment, true); var result = sb.ToString(); - await Assert.That(result).Contains("__KVOObservable"); - await Assert.That(result).Contains("true)"); + await Assert.That(result).Contains(KVOObservableLocal); + await Assert.That(result).Contains(TrueFragment); } - /// - /// Verifies KVO plugin inline observation variable emits KVOObservable. - /// + /// Verifies KVO plugin inline observation variable emits KVOObservable. /// A task representing the asynchronous test operation. [Test] public async Task KVOPlugin_EmitInlineObservationVariable_EmitsKVOObservable() { var plugin = new KVOObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitInlineObservationVariable(sb, "source", segment, "global::TestApp.MyView", "sourceObs"); + plugin.EmitInlineObservationVariable(sb, SourceName, segment, MyViewTypeName, SourceObsName); var result = sb.ToString(); - await Assert.That(result).Contains("__KVOObservable"); - await Assert.That(result).Contains("var sourceObs"); + await Assert.That(result).Contains(KVOObservableLocal); + await Assert.That(result).Contains(SourceObsDeclaration); } - /// - /// Verifies KVO key path for boolean property uses "is" prefix. - /// + /// Verifies KVO key path for boolean property uses "is" prefix. /// A task representing the asynchronous test operation. [Test] public async Task KVOPlugin_BooleanProperty_UsesIsPrefix() @@ -660,14 +642,12 @@ public async Task KVOPlugin_BooleanProperty_UsesIsPrefix() var sb = new StringBuilder(); var segment = ModelFactory.CreatePropertyPathSegment("Enabled", "bool"); - plugin.EmitShallowObservation(sb, "obj", segment, "global::TestApp.MyView", false, true); + plugin.EmitShallowObservation(sb, "obj", segment, MyViewTypeName, false, true); await Assert.That(sb.ToString()).Contains("\"isEnabled\""); } - /// - /// Verifies KVO key path for boolean property already starting with "Is" does not double-prefix. - /// + /// Verifies KVO key path for boolean property already starting with "Is" does not double-prefix. /// A task representing the asynchronous test operation. [Test] public async Task KVOPlugin_BooleanPropertyAlreadyStartingWithIs_DoesNotDoublePrefix() @@ -676,30 +656,26 @@ public async Task KVOPlugin_BooleanPropertyAlreadyStartingWithIs_DoesNotDoublePr var sb = new StringBuilder(); var segment = ModelFactory.CreatePropertyPathSegment("IsEnabled", "bool"); - plugin.EmitShallowObservation(sb, "obj", segment, "global::TestApp.MyView", false, true); + plugin.EmitShallowObservation(sb, "obj", segment, MyViewTypeName, false, true); await Assert.That(sb.ToString()).Contains("\"isEnabled\""); } - /// - /// Verifies KVO key path for empty property name returns empty string. - /// + /// Verifies KVO key path for empty property name returns empty string. /// A task representing the asynchronous test operation. [Test] public async Task KVOPlugin_EmptyPropertyName_ReturnsEmpty() { var plugin = new KVOObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment(string.Empty, "string"); + var segment = ModelFactory.CreatePropertyPathSegment(string.Empty, StringName); - plugin.EmitShallowObservation(sb, "obj", segment, "global::TestApp.MyView", false, true); + plugin.EmitShallowObservation(sb, "obj", segment, MyViewTypeName, false, true); await Assert.That(sb.ToString()).Contains("\"\""); } - /// - /// Verifies KVO plugin emits helper classes with __KVOObserver and __KVOObservable. - /// + /// Verifies KVO plugin emits helper classes with __KVOObserver and __KVOObservable. /// A task representing the asynchronous test operation. [Test] public async Task KVOPlugin_EmitHelperClasses_EmitsKVOClasses() @@ -711,105 +687,92 @@ public async Task KVOPlugin_EmitHelperClasses_EmitsKVOClasses() var result = sb.ToString(); await Assert.That(result).Contains("__KVOObserver"); - await Assert.That(result).Contains("__KVOObservable"); + await Assert.That(result).Contains(KVOObservableLocal); await Assert.That(result).Contains("AddObserver"); } - /// - /// Verifies KVO plugin shallow observation emits both before/after change variants correctly. - /// + /// Verifies KVO plugin shallow observation emits both before/after change variants correctly. /// A task representing the asynchronous test operation. [Test] public async Task KVOPlugin_EmitShallowObservation_BeforeChange_EmitsKVOObservable() { var plugin = new KVOObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitShallowObservation(sb, "obj", segment, "global::TestApp.MyView", true, true); + plugin.EmitShallowObservation(sb, "obj", segment, MyViewTypeName, true, true); var result = sb.ToString(); - await Assert.That(result).Contains("__KVOObservable"); + await Assert.That(result).Contains(KVOObservableLocal); await Assert.That(result).Contains("true, true"); } // ========== AndroidObservationPlugin ========== - - /// - /// Verifies Android plugin shallow observation variable emits ReturnObservable. - /// + /// Verifies Android plugin shallow observation variable emits ReturnObservable. /// A task representing the asynchronous test operation. [Test] public async Task AndroidPlugin_EmitShallowObservationVariable_EmitsReturnObservable() { var plugin = new AndroidObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitShallowObservationVariable(sb, "obj", segment, "global::TestApp.MyAndroidView", false, "__obs0"); + plugin.EmitShallowObservationVariable(sb, "obj", segment, MyAndroidViewTypeName, false, Obs0Local); var result = sb.ToString(); - await Assert.That(result).Contains("ReturnObservable"); - await Assert.That(result).Contains("var __obs0"); + await Assert.That(result).Contains(ReturnObservableName); + await Assert.That(result).Contains(Obs0Declaration); } - /// - /// Verifies Android plugin deep chain root segment emits ReturnObservable. - /// + /// Verifies Android plugin deep chain root segment emits ReturnObservable. /// A task representing the asynchronous test operation. [Test] public async Task AndroidPlugin_EmitDeepChainRootSegment_EmitsReturnObservable() { var plugin = new AndroidObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitDeepChainRootSegment(sb, "obj", segment, "global::TestApp.MyAndroidView", false, "__obs0"); + plugin.EmitDeepChainRootSegment(sb, "obj", segment, MyAndroidViewTypeName, false, Obs0Local); var result = sb.ToString(); - await Assert.That(result).Contains("ReturnObservable"); - await Assert.That(result).Contains("var __obs0"); + await Assert.That(result).Contains(ReturnObservableName); + await Assert.That(result).Contains(Obs0Declaration); } - /// - /// Verifies Android plugin deep chain inner segment emits ReturnObservable with Switch. - /// + /// Verifies Android plugin deep chain inner segment emits ReturnObservable with Switch. /// A task representing the asynchronous test operation. [Test] public async Task AndroidPlugin_EmitDeepChainInnerSegment_EmitsReturnObservable() { var plugin = new AndroidObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("City", "string", "global::TestApp.Address"); + var segment = ModelFactory.CreatePropertyPathSegment("City", StringName, AddressTypeName); - plugin.EmitDeepChainInnerSegment(sb, "__obs0", "__obs1", "__p1", segment, false); + plugin.EmitDeepChainInnerSegment(sb, Obs0Local, Obs1Local, "__p1", segment, false); var result = sb.ToString(); - await Assert.That(result).Contains("ReturnObservable"); - await Assert.That(result).Contains("Switch"); + await Assert.That(result).Contains(ReturnObservableName); + await Assert.That(result).Contains(SwitchName); } - /// - /// Verifies Android plugin inline observation variable emits ReturnObservable. - /// + /// Verifies Android plugin inline observation variable emits ReturnObservable. /// A task representing the asynchronous test operation. [Test] public async Task AndroidPlugin_EmitInlineObservationVariable_EmitsReturnObservable() { var plugin = new AndroidObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitInlineObservationVariable(sb, "source", segment, "global::TestApp.MyAndroidView", "sourceObs"); + plugin.EmitInlineObservationVariable(sb, SourceName, segment, MyAndroidViewTypeName, SourceObsName); var result = sb.ToString(); - await Assert.That(result).Contains("ReturnObservable"); - await Assert.That(result).Contains("var sourceObs"); + await Assert.That(result).Contains(ReturnObservableName); + await Assert.That(result).Contains(SourceObsDeclaration); } - /// - /// Verifies Android plugin EmitHelperClasses is a no-op. - /// + /// Verifies Android plugin EmitHelperClasses is a no-op. /// A task representing the asynchronous test operation. [Test] public async Task AndroidPlugin_EmitHelperClasses_IsNoOp() @@ -822,140 +785,121 @@ public async Task AndroidPlugin_EmitHelperClasses_IsNoOp() await Assert.That(sb.Length).IsEqualTo(0); } - /// - /// Verifies Android plugin properties. - /// + /// Verifies Android plugin properties. /// A task representing the asynchronous test operation. [Test] public async Task AndroidPlugin_Properties_AreCorrect() { + const int ExpectedPluginAffinity = 5; var plugin = new AndroidObservationPlugin(); - await Assert.That(plugin.Affinity).IsEqualTo(5); + await Assert.That(plugin.Affinity).IsEqualTo(ExpectedPluginAffinity); await Assert.That(plugin.ObservationKind).IsEqualTo("Android"); await Assert.That(plugin.SupportsBeforeChanged).IsFalse(); await Assert.That(plugin.RequiresHelperClasses).IsFalse(); } // ========== Shallow observation with includeStartWith=false ========== - - /// - /// Verifies INPC plugin shallow observation with includeStartWith=false emits "false". - /// + /// Verifies INPC plugin shallow observation with includeStartWith=false emits "false". /// A task representing the asynchronous test operation. [Test] public async Task INPCPlugin_EmitShallowObservation_NoStartWith_EmitsFalse() { var plugin = new INPCObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Name", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Name", StringName); plugin.EmitShallowObservation(sb, "obj", segment, "global::TestApp.MyViewModel", false, false); - await Assert.That(sb.ToString()).Contains("false)"); + await Assert.That(sb.ToString()).Contains(FalseFragment); } - /// - /// Verifies ReactiveObject plugin shallow observation with includeStartWith=false emits "false". - /// + /// Verifies ReactiveObject plugin shallow observation with includeStartWith=false emits "false". /// A task representing the asynchronous test operation. [Test] public async Task ReactiveObjectPlugin_EmitShallowObservation_NoStartWith_EmitsFalse() { var plugin = new ReactiveObjectObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Name", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Name", StringName); plugin.EmitShallowObservation(sb, "obj", segment, "global::TestApp.MyViewModel", false, false); - await Assert.That(sb.ToString()).Contains("false)"); + await Assert.That(sb.ToString()).Contains(FalseFragment); } - /// - /// Verifies WPF plugin shallow observation with includeStartWith=false emits "false". - /// + /// Verifies WPF plugin shallow observation with includeStartWith=false emits "false". /// A task representing the asynchronous test operation. [Test] public async Task WpfPlugin_EmitShallowObservation_NoStartWith_EmitsFalse() { var plugin = new WpfObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitShallowObservation(sb, "obj", segment, "global::TestApp.MyControl", false, false); + plugin.EmitShallowObservation(sb, "obj", segment, MyControlTypeName, false, false); - await Assert.That(sb.ToString()).Contains("false)"); + await Assert.That(sb.ToString()).Contains(FalseFragment); } - /// - /// Verifies WinForms plugin shallow observation with includeStartWith=false emits "false". - /// + /// Verifies WinForms plugin shallow observation with includeStartWith=false emits "false". /// A task representing the asynchronous test operation. [Test] public async Task WinFormsPlugin_EmitShallowObservation_NoStartWith_EmitsFalse() { var plugin = new WinFormsObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitShallowObservation(sb, "obj", segment, "global::TestApp.MyTextBox", false, false); + plugin.EmitShallowObservation(sb, "obj", segment, MyTextBoxTypeName, false, false); - await Assert.That(sb.ToString()).Contains("false)"); + await Assert.That(sb.ToString()).Contains(FalseFragment); } - /// - /// Verifies WinUI plugin shallow observation with includeStartWith=false emits "false". - /// + /// Verifies WinUI plugin shallow observation with includeStartWith=false emits "false". /// A task representing the asynchronous test operation. [Test] public async Task WinUIPlugin_EmitShallowObservation_NoStartWith_EmitsFalse() { var plugin = new WinUIObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitShallowObservation(sb, "obj", segment, "global::TestApp.MyControl", false, false); + plugin.EmitShallowObservation(sb, "obj", segment, MyControlTypeName, false, false); - await Assert.That(sb.ToString()).Contains("false)"); + await Assert.That(sb.ToString()).Contains(FalseFragment); } - /// - /// Verifies KVO plugin shallow observation with includeStartWith=false emits "false". - /// + /// Verifies KVO plugin shallow observation with includeStartWith=false emits "false". /// A task representing the asynchronous test operation. [Test] public async Task KVOPlugin_EmitShallowObservation_NoStartWith_EmitsFalse() { var plugin = new KVOObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitShallowObservation(sb, "obj", segment, "global::TestApp.MyView", false, false); + plugin.EmitShallowObservation(sb, "obj", segment, MyViewTypeName, false, false); await Assert.That(sb.ToString()).Contains("false, false)"); } - /// - /// Verifies Android plugin shallow observation emits ReturnObservable. - /// + /// Verifies Android plugin shallow observation emits ReturnObservable. /// A task representing the asynchronous test operation. [Test] public async Task AndroidPlugin_EmitShallowObservation_EmitsReturnObservable() { var plugin = new AndroidObservationPlugin(); var sb = new StringBuilder(); - var segment = ModelFactory.CreatePropertyPathSegment("Text", "string"); + var segment = ModelFactory.CreatePropertyPathSegment("Text", StringName); - plugin.EmitShallowObservation(sb, "obj", segment, "global::TestApp.MyAndroidView", false, true); + plugin.EmitShallowObservation(sb, "obj", segment, MyAndroidViewTypeName, false, true); - await Assert.That(sb.ToString()).Contains("ReturnObservable"); + await Assert.That(sb.ToString()).Contains(ReturnObservableName); } // ========== INPCObservationPlugin ========== - - /// - /// Verifies INPC plugin EmitHelperClasses is a no-op. - /// + /// Verifies INPC plugin EmitHelperClasses is a no-op. /// A task representing the asynchronous test operation. [Test] public async Task INPCPlugin_EmitHelperClasses_IsNoOp() @@ -969,10 +913,7 @@ public async Task INPCPlugin_EmitHelperClasses_IsNoOp() } // ========== ReactiveObjectObservationPlugin ========== - - /// - /// Verifies ReactiveObject plugin EmitHelperClasses is a no-op. - /// + /// Verifies ReactiveObject plugin EmitHelperClasses is a no-op. /// A task representing the asynchronous test operation. [Test] public async Task ReactiveObjectPlugin_EmitHelperClasses_IsNoOp() @@ -986,22 +927,18 @@ public async Task ReactiveObjectPlugin_EmitHelperClasses_IsNoOp() } // ========== ObservationPluginRegistry ========== - - /// - /// Verifies GetPlugin returns the correct plugin by index. - /// + /// Verifies GetPlugin returns the correct plugin by index. /// A task representing the asynchronous test operation. [Test] public async Task Registry_GetPlugin_ReturnsCorrectPlugin() { + const int ExpectedPlugin0Affinity = 15; var plugin0 = ObservationPluginRegistry.GetPlugin(0); - await Assert.That(plugin0.Affinity).IsEqualTo(15); // KVO has highest affinity + await Assert.That(plugin0.Affinity).IsEqualTo(ExpectedPlugin0Affinity); // KVO has highest affinity } - /// - /// Verifies GetPluginByKind returns null for unknown kind. - /// + /// Verifies GetPluginByKind returns null for unknown kind. /// A task representing the asynchronous test operation. [Test] public async Task Registry_GetPluginByKind_UnknownKind_ReturnsNull() @@ -1011,10 +948,12 @@ public async Task Registry_GetPluginByKind_UnknownKind_ReturnsNull() await Assert.That(plugin).IsNull(); } - /// - /// Verifies Count returns the correct number of plugins. - /// + /// Verifies Count returns the correct number of plugins. /// A task representing the asynchronous test operation. [Test] - public async Task Registry_Count_Returns7() => await Assert.That(ObservationPluginRegistry.Count).IsEqualTo(7); + public async Task Registry_Count_Returns7() + { + const int ExpectedPluginCount = 7; + await Assert.That(ObservationPluginRegistry.Count).IsEqualTo(ExpectedPluginCount); + } } diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/RoslynHelpersTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/RoslynHelpersTests.cs index 8ea5f24..2c25fe4 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/RoslynHelpersTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/RoslynHelpersTests.cs @@ -6,14 +6,10 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests; -/// -/// Tests for predicate methods. -/// +/// Tests for predicate methods. public class RoslynHelpersTests { - /// - /// Verifies that GetMemberAccessName returns the method name for a member access invocation. - /// + /// Verifies that GetMemberAccessName returns the method name for a member access invocation. /// A task representing the asynchronous test operation. [Test] public async Task GetMemberAccessName_MemberAccessInvocation_ReturnsName() @@ -26,9 +22,7 @@ public async Task GetMemberAccessName_MemberAccessInvocation_ReturnsName() await Assert.That(result).IsEqualTo("WhenChanged"); } - /// - /// Verifies that GetMemberAccessName returns null for a non-invocation node. - /// + /// Verifies that GetMemberAccessName returns null for a non-invocation node. /// A task representing the asynchronous test operation. [Test] public async Task GetMemberAccessName_NonInvocation_ReturnsNull() @@ -40,9 +34,7 @@ public async Task GetMemberAccessName_NonInvocation_ReturnsNull() await Assert.That(result).IsNull(); } - /// - /// Verifies that GetMemberAccessName returns null for a simple invocation without member access. - /// + /// Verifies that GetMemberAccessName returns null for a simple invocation without member access. /// A task representing the asynchronous test operation. [Test] public async Task GetMemberAccessName_SimpleInvocation_ReturnsNull() @@ -54,9 +46,7 @@ public async Task GetMemberAccessName_SimpleInvocation_ReturnsNull() await Assert.That(result).IsNull(); } - /// - /// Verifies IsBindSpecificInvocation returns true only for Bind method name. - /// + /// Verifies IsBindSpecificInvocation returns true only for Bind method name. /// A task representing the asynchronous test operation. [Test] public async Task IsBindSpecificInvocation_BindMethod_ReturnsTrue() @@ -69,9 +59,7 @@ public async Task IsBindSpecificInvocation_BindMethod_ReturnsTrue() await Assert.That(result).IsTrue(); } - /// - /// Verifies IsBindSpecificInvocation returns false for BindOneWay method. - /// + /// Verifies IsBindSpecificInvocation returns false for BindOneWay method. /// A task representing the asynchronous test operation. [Test] public async Task IsBindSpecificInvocation_BindOneWayMethod_ReturnsFalse() @@ -84,9 +72,7 @@ public async Task IsBindSpecificInvocation_BindOneWayMethod_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies IsBindOneWaySpecificInvocation returns true for BindOneWay. - /// + /// Verifies IsBindOneWaySpecificInvocation returns true for BindOneWay. /// A task representing the asynchronous test operation. [Test] public async Task IsBindOneWaySpecificInvocation_BindOneWayMethod_ReturnsTrue() @@ -99,9 +85,7 @@ public async Task IsBindOneWaySpecificInvocation_BindOneWayMethod_ReturnsTrue() await Assert.That(result).IsTrue(); } - /// - /// Verifies IsBindOneWaySpecificInvocation returns false for BindTwoWay. - /// + /// Verifies IsBindOneWaySpecificInvocation returns false for BindTwoWay. /// A task representing the asynchronous test operation. [Test] public async Task IsBindOneWaySpecificInvocation_BindTwoWayMethod_ReturnsFalse() @@ -114,9 +98,7 @@ public async Task IsBindOneWaySpecificInvocation_BindTwoWayMethod_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies IsBindTwoWaySpecificInvocation returns true for BindTwoWay. - /// + /// Verifies IsBindTwoWaySpecificInvocation returns true for BindTwoWay. /// A task representing the asynchronous test operation. [Test] public async Task IsBindTwoWaySpecificInvocation_BindTwoWayMethod_ReturnsTrue() @@ -129,9 +111,7 @@ public async Task IsBindTwoWaySpecificInvocation_BindTwoWayMethod_ReturnsTrue() await Assert.That(result).IsTrue(); } - /// - /// Verifies IsOneWayBindSpecificInvocation returns true for OneWayBind. - /// + /// Verifies IsOneWayBindSpecificInvocation returns true for OneWayBind. /// A task representing the asynchronous test operation. [Test] public async Task IsOneWayBindSpecificInvocation_OneWayBindMethod_ReturnsTrue() @@ -144,9 +124,7 @@ public async Task IsOneWayBindSpecificInvocation_OneWayBindMethod_ReturnsTrue() await Assert.That(result).IsTrue(); } - /// - /// Verifies IsOneWayBindSpecificInvocation returns false for Bind. - /// + /// Verifies IsOneWayBindSpecificInvocation returns false for Bind. /// A task representing the asynchronous test operation. [Test] public async Task IsOneWayBindSpecificInvocation_BindMethod_ReturnsFalse() @@ -159,9 +137,7 @@ public async Task IsOneWayBindSpecificInvocation_BindMethod_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies specific predicates return false for non-invocation nodes. - /// + /// Verifies specific predicates return false for non-invocation nodes. /// A task representing the asynchronous test operation. [Test] public async Task SpecificPredicates_NonInvocation_ReturnFalse() diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/RuntimeExecution/BindOneWayRuntimeTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/RuntimeExecution/BindOneWayRuntimeTests.cs index d8c3a51..227cd07 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/RuntimeExecution/BindOneWayRuntimeTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/RuntimeExecution/BindOneWayRuntimeTests.cs @@ -13,9 +13,13 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests.RuntimeExecution; /// public class BindOneWayRuntimeTests { - /// - /// Verifies that BindOneWay generates dispatch and registration files. - /// + /// The BindOneWayDispatch.g.cs name these tests generate against. + private const string BindOneWayDispatchgcsName = "BindOneWayDispatch.g.cs"; + + /// The BindTwoWayDispatch.g.cs name these tests generate against. + private const string BindTwoWayDispatchgcsName = "BindTwoWayDispatch.g.cs"; + + /// Verifies that BindOneWay generates dispatch and registration files. /// A task representing the asynchronous test operation. [Test] public async Task StringBinding_GeneratesDispatchAndRegistration() @@ -54,15 +58,13 @@ public void Test() var result = TestHelper.RunGenerator(source, LanguageVersion.CSharp10); await result.HasNoGeneratorDiagnostics(); - await result.HasGeneratedSource("BindOneWayDispatch.g.cs"); + await result.HasGeneratedSource(BindOneWayDispatchgcsName); await result.HasGeneratedSource("GeneratedBinderRegistration.g.cs"); - await result.GeneratedSourceContains("BindOneWayDispatch.g.cs", "NameText"); - await result.GeneratedSourceContains("BindOneWayDispatch.g.cs", "Name"); + await result.GeneratedSourceContains(BindOneWayDispatchgcsName, "NameText"); + await result.GeneratedSourceContains(BindOneWayDispatchgcsName, "Name"); } - /// - /// Verifies that WhenChanging generates dispatch code with PropertyChanging subscription. - /// + /// Verifies that WhenChanging generates dispatch code with PropertyChanging subscription. /// A task representing the asynchronous test operation. [Test] public async Task WhenChanging_GeneratesPropertyChangingSubscription() @@ -100,9 +102,7 @@ public void Test() await result.GeneratedSourceContains("WhenChangingDispatch.g.cs", "PropertyChanging"); } - /// - /// Verifies that WhenAnyValue generates dispatch code. - /// + /// Verifies that WhenAnyValue generates dispatch code. /// A task representing the asynchronous test operation. [Test] public async Task WhenAnyValue_GeneratesDispatch() @@ -140,9 +140,7 @@ public void Test() await result.GeneratedSourceContains("WhenAnyValueDispatch.g.cs", "CombineLatest"); } - /// - /// Verifies that BindTwoWay generates dispatch code for two-way binding. - /// + /// Verifies that BindTwoWay generates dispatch code for two-way binding. /// A task representing the asynchronous test operation. [Test] public async Task BindTwoWay_GeneratesDispatch() @@ -181,8 +179,8 @@ public void Test() var result = TestHelper.RunGenerator(source, LanguageVersion.CSharp10); await result.HasNoGeneratorDiagnostics(); - await result.HasGeneratedSource("BindTwoWayDispatch.g.cs"); - await result.GeneratedSourceContains("BindTwoWayDispatch.g.cs", "Name"); - await result.GeneratedSourceContains("BindTwoWayDispatch.g.cs", "NameText"); + await result.HasGeneratedSource(BindTwoWayDispatchgcsName); + await result.GeneratedSourceContains(BindTwoWayDispatchgcsName, "Name"); + await result.GeneratedSourceContains(BindTwoWayDispatchgcsName, "NameText"); } } diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/RuntimeExecution/WhenChangedRuntimeTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/RuntimeExecution/WhenChangedRuntimeTests.cs index 062439a..f22c6ba 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/RuntimeExecution/WhenChangedRuntimeTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/RuntimeExecution/WhenChangedRuntimeTests.cs @@ -13,9 +13,10 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests.RuntimeExecution; /// public class WhenChangedRuntimeTests { - /// - /// Verifies that single-property WhenChanged generates a dispatch file with correct structure. - /// + /// The WhenChangedDispatch.g.cs name these tests generate against. + private const string WhenChangedDispatchgcsName = "WhenChangedDispatch.g.cs"; + + /// Verifies that single-property WhenChanged generates a dispatch file with correct structure. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_GeneratesDispatchAndRegistration() @@ -61,15 +62,13 @@ public void Test() await result.CompilationSucceeds(); await result.HasNoGeneratorDiagnostics(); - await result.HasGeneratedSource("WhenChangedDispatch.g.cs"); + await result.HasGeneratedSource(WhenChangedDispatchgcsName); await result.HasGeneratedSource("GeneratedBinderRegistration.g.cs"); - await result.GeneratedSourceContains("WhenChangedDispatch.g.cs", "PropertyChanged"); - await result.GeneratedSourceContains("WhenChangedDispatch.g.cs", "Name"); + await result.GeneratedSourceContains(WhenChangedDispatchgcsName, "PropertyChanged"); + await result.GeneratedSourceContains(WhenChangedDispatchgcsName, "Name"); } - /// - /// Verifies that multi-property WhenChanged generates CombineLatest observation code. - /// + /// Verifies that multi-property WhenChanged generates CombineLatest observation code. /// A task representing the asynchronous test operation. [Test] public async Task MultiProperty_GeneratesCombineLatest() @@ -103,13 +102,11 @@ public void Test() await result.CompilationSucceeds(); await result.HasNoGeneratorDiagnostics(); - await result.HasGeneratedSource("WhenChangedDispatch.g.cs"); - await result.GeneratedSourceContains("WhenChangedDispatch.g.cs", "CombineLatest"); + await result.HasGeneratedSource(WhenChangedDispatchgcsName); + await result.GeneratedSourceContains(WhenChangedDispatchgcsName, "CombineLatest"); } - /// - /// Verifies that deep chain WhenChanged generates Switch-based re-subscription code. - /// + /// Verifies that deep chain WhenChanged generates Switch-based re-subscription code. /// A task representing the asynchronous test operation. [Test] public async Task DeepChain_GeneratesSwitchPattern() @@ -148,13 +145,11 @@ public void Test() await result.CompilationSucceeds(); await result.HasNoGeneratorDiagnostics(); - await result.HasGeneratedSource("WhenChangedDispatch.g.cs"); - await result.GeneratedSourceContains("WhenChangedDispatch.g.cs", "Switch"); + await result.HasGeneratedSource(WhenChangedDispatchgcsName); + await result.GeneratedSourceContains(WhenChangedDispatchgcsName, "Switch"); } - /// - /// Verifies that WhenChanged with a selector generates the selector invocation. - /// + /// Verifies that WhenChanged with a selector generates the selector invocation. /// A task representing the asynchronous test operation. [Test] public async Task WithSelector_GeneratesSelectorInvocation() @@ -188,7 +183,7 @@ public void Test() await result.CompilationSucceeds(); await result.HasNoGeneratorDiagnostics(); - await result.HasGeneratedSource("WhenChangedDispatch.g.cs"); - await result.GeneratedSourceContains("WhenChangedDispatch.g.cs", "selector"); + await result.HasGeneratedSource(WhenChangedDispatchgcsName); + await result.GeneratedSourceContains(WhenChangedDispatchgcsName, "selector"); } } diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/ViewLocatorDispatchGeneratorTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/ViewLocatorDispatchGeneratorTests.cs index 11e5ed6..d9d3c5f 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/ViewLocatorDispatchGeneratorTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/ViewLocatorDispatchGeneratorTests.cs @@ -13,9 +13,7 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests; /// public class ViewLocatorDispatchGeneratorTests { - /// - /// Verifies that a single IViewFor<T> implementation generates correct dispatch code. - /// + /// Verifies that a single IViewFor<T> implementation generates correct dispatch code. /// A task representing the asynchronous test operation. [Test] public Task SingleViewForImplementation() @@ -46,9 +44,7 @@ object ReactiveUI.Binding.IViewFor.ViewModel return TestHelper.TestPass(source, typeof(ViewLocatorDispatchGeneratorTests)); } - /// - /// Verifies that multiple IViewFor<T> implementations generate multiple dispatch branches. - /// + /// Verifies that multiple IViewFor<T> implementations generate multiple dispatch branches. /// A task representing the asynchronous test operation. [Test] public Task MultipleViewForImplementations() @@ -95,9 +91,7 @@ object ReactiveUI.Binding.IViewFor.ViewModel return TestHelper.TestPass(source, typeof(ViewLocatorDispatchGeneratorTests)); } - /// - /// Verifies that a view without a parameterless constructor generates service-locator-only dispatch. - /// + /// Verifies that a view without a parameterless constructor generates service-locator-only dispatch. /// A task representing the asynchronous test operation. [Test] public Task ViewWithoutParameterlessConstructor() @@ -135,9 +129,7 @@ object ReactiveUI.Binding.IViewFor.ViewModel return TestHelper.TestPass(source, typeof(ViewLocatorDispatchGeneratorTests)); } - /// - /// Verifies that abstract classes implementing IViewFor<T> are excluded from dispatch. - /// + /// Verifies that abstract classes implementing IViewFor<T> are excluded from dispatch. /// A task representing the asynchronous test operation. [Test] public Task AbstractViewIsExcluded() @@ -172,9 +164,7 @@ object ReactiveUI.Binding.IViewFor.ViewModel .UseMethodName("AbstractExcl"); } - /// - /// Verifies that a view with a private constructor generates service-locator-only dispatch (no direct construction). - /// + /// Verifies that a view with a private constructor generates service-locator-only dispatch (no direct construction). /// A task representing the asynchronous test operation. [Test] public Task ViewWithPrivateConstructor() @@ -207,9 +197,7 @@ object ReactiveUI.Binding.IViewFor.ViewModel return TestHelper.TestPass(source, typeof(ViewLocatorDispatchGeneratorTests)); } - /// - /// Verifies that a class not implementing IViewFor produces no ViewDispatch output. - /// + /// Verifies that a class not implementing IViewFor produces no ViewDispatch output. /// A task representing the asynchronous test operation. [Test] public Task NonViewForClass_NoDispatch() @@ -233,9 +221,7 @@ public class PlainViewModel : INotifyPropertyChanged .UseMethodName("NoViewFor"); } - /// - /// Verifies that duplicate IViewFor<T> implementations for the same view model are deduplicated. - /// + /// Verifies that duplicate IViewFor<T> implementations for the same view model are deduplicated. /// A task representing the asynchronous test operation. [Test] public Task DuplicateViewModelsAreDeduplicated() @@ -276,9 +262,7 @@ object ReactiveUI.Binding.IViewFor.ViewModel return TestHelper.TestPass(source, typeof(ViewLocatorDispatchGeneratorTests)); } - /// - /// Verifies that a view marked with [ExcludeFromViewRegistration] is not included in dispatch. - /// + /// Verifies that a view marked with [ExcludeFromViewRegistration] is not included in dispatch. /// A task representing the asynchronous test operation. [Test] public Task ExcludedViewIsSkipped() @@ -314,9 +298,7 @@ object ReactiveUI.Binding.IViewFor.ViewModel .UseMethodName("ExclAttr"); } - /// - /// Verifies that a view marked with [SingleInstanceView] generates singleton dispatch code. - /// + /// Verifies that a view marked with [SingleInstanceView] generates singleton dispatch code. /// A task representing the asynchronous test operation. [Test] public Task SingleInstanceViewGeneratesSingletonCache() @@ -348,9 +330,7 @@ object ReactiveUI.Binding.IViewFor.ViewModel return TestHelper.TestPass(source, typeof(ViewLocatorDispatchGeneratorTests)); } - /// - /// Verifies that a view marked with [ViewContract] generates contract-aware dispatch code. - /// + /// Verifies that a view marked with [ViewContract] generates contract-aware dispatch code. /// A task representing the asynchronous test operation. [Test] public Task ViewContractGeneratesContractDispatch() diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAG.MI_STS#WhenAnyDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAG.MI_STS#WhenAnyDispatch.g.verified.cs index 1f0e5eb..e2e0606 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAG.MI_STS#WhenAnyDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAG.MI_STS#WhenAnyDispatch.g.verified.cs @@ -24,16 +24,16 @@ internal static partial class __ReactiveUIGeneratedBindings if (property1Expression == "x => x.FirstName") { - return __WhenAny_00002A5206691D9A(objectToMonitor, selector); + return __WhenAny_00002A5206691BE8(objectToMonitor, selector); } else if (property1Expression == "x => x.LastName") { - return __WhenAny_00002A522B790428(objectToMonitor, selector); + return __WhenAny_00002A522B790276(objectToMonitor, selector); } throw new global::System.InvalidOperationException("No generated WhenAny dispatch matched. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IObservable __WhenAny_00002A5206691D9A(global::SharedScenarios.WhenAny.MultipleInvocationsSameType.MyViewModel obj, global::System.Func, string> selector) + private static global::System.IObservable __WhenAny_00002A5206691BE8(global::SharedScenarios.WhenAny.MultipleInvocationsSameType.MyViewModel obj, global::System.Func, string> selector) { var __propObs0 = new global::ReactiveUI.Binding.Observables.PropertyObservable( obj, @@ -45,7 +45,7 @@ internal static partial class __ReactiveUIGeneratedBindings value => selector(new global::ReactiveUI.Binding.ObservedChange(obj, null, value))); } - private static global::System.IObservable __WhenAny_00002A522B790428(global::SharedScenarios.WhenAny.MultipleInvocationsSameType.MyViewModel obj, global::System.Func, string> selector) + private static global::System.IObservable __WhenAny_00002A522B790276(global::SharedScenarios.WhenAny.MultipleInvocationsSameType.MyViewModel obj, global::System.Func, string> selector) { var __propObs0 = new global::ReactiveUI.Binding.Observables.PropertyObservable( obj, diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAG.MP_2P#WhenAnyDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAG.MP_2P#WhenAnyDispatch.g.verified.cs index f38645c..79ca947 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAG.MP_2P#WhenAnyDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAG.MP_2P#WhenAnyDispatch.g.verified.cs @@ -27,12 +27,12 @@ internal static partial class __ReactiveUIGeneratedBindings if (property1Expression == "x => x.FirstName" && property2Expression == "x => x.LastName") { - return __WhenAny_7FFFD022211E6924(objectToMonitor, selector); + return __WhenAny_7FFFD022211E6772(objectToMonitor, selector); } throw new global::System.InvalidOperationException("No generated WhenAny dispatch matched. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IObservable __WhenAny_7FFFD022211E6924(global::SharedScenarios.WhenAny.MultiPropertyTwoProperties.MyViewModel obj, global::System.Func, global::ReactiveUI.Binding.IObservedChange, string> selector) + private static global::System.IObservable __WhenAny_7FFFD022211E6772(global::SharedScenarios.WhenAny.MultiPropertyTwoProperties.MyViewModel obj, global::System.Func, global::ReactiveUI.Binding.IObservedChange, string> selector) { var __propObs0 = new global::ReactiveUI.Binding.Observables.PropertyObservable( obj, diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAG.MP_DC#WhenAnyDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAG.MP_DC#WhenAnyDispatch.g.verified.cs index bb863a3..933a4f7 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAG.MP_DC#WhenAnyDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAG.MP_DC#WhenAnyDispatch.g.verified.cs @@ -27,12 +27,12 @@ internal static partial class __ReactiveUIGeneratedBindings if (property1Expression == "x => x.Child.Name" && property2Expression == "x => x.Title") { - return __WhenAny_7FFFD8112D4F4A57(objectToMonitor, selector); + return __WhenAny_7FFFD8112D4F47EB(objectToMonitor, selector); } throw new global::System.InvalidOperationException("No generated WhenAny dispatch matched. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IObservable __WhenAny_7FFFD8112D4F4A57(global::SharedScenarios.WhenAny.MultiPropertyDeepChain.ParentViewModel obj, global::System.Func, global::ReactiveUI.Binding.IObservedChange, string> selector) + private static global::System.IObservable __WhenAny_7FFFD8112D4F47EB(global::SharedScenarios.WhenAny.MultiPropertyDeepChain.ParentViewModel obj, global::System.Func, global::ReactiveUI.Binding.IObservedChange, string> selector) { var __propObs0_s0 = (global::System.IObservable)new global::ReactiveUI.Binding.Observables.PropertyObservable( obj, diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAG.SP_DC#WhenAnyDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAG.SP_DC#WhenAnyDispatch.g.verified.cs index 6295135..aa1449b 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAG.SP_DC#WhenAnyDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAG.SP_DC#WhenAnyDispatch.g.verified.cs @@ -24,12 +24,12 @@ internal static partial class __ReactiveUIGeneratedBindings if (property1Expression == "x => x.Child.Name") { - return __WhenAny_0000044C0197403E(objectToMonitor, selector); + return __WhenAny_0000044C01973E4E(objectToMonitor, selector); } throw new global::System.InvalidOperationException("No generated WhenAny dispatch matched. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IObservable __WhenAny_0000044C0197403E(global::SharedScenarios.WhenAny.DeepPropertyChain.ParentViewModel obj, global::System.Func, string> selector) + private static global::System.IObservable __WhenAny_0000044C01973E4E(global::SharedScenarios.WhenAny.DeepPropertyChain.ParentViewModel obj, global::System.Func, string> selector) { var __propObs0_s0 = (global::System.IObservable)new global::ReactiveUI.Binding.Observables.PropertyObservable( obj, diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAG.SP_INPC#WhenAnyDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAG.SP_INPC#WhenAnyDispatch.g.verified.cs index 6ff058e..1e27895 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAG.SP_INPC#WhenAnyDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAG.SP_INPC#WhenAnyDispatch.g.verified.cs @@ -24,12 +24,12 @@ internal static partial class __ReactiveUIGeneratedBindings if (property1Expression == "x => x.Name") { - return __WhenAny_00002E2F49F125B1(objectToMonitor, selector); + return __WhenAny_00002E2F49F1247B(objectToMonitor, selector); } throw new global::System.InvalidOperationException("No generated WhenAny dispatch matched. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IObservable __WhenAny_00002E2F49F125B1(global::SharedScenarios.WhenAny.SinglePropertyINPC.MyViewModel obj, global::System.Func, string> selector) + private static global::System.IObservable __WhenAny_00002E2F49F1247B(global::SharedScenarios.WhenAny.SinglePropertyINPC.MyViewModel obj, global::System.Func, string> selector) { var __propObs0 = new global::ReactiveUI.Binding.Observables.PropertyObservable( obj, diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAG.SP_INPC_CFP#WhenAnyDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAG.SP_INPC_CFP#WhenAnyDispatch.g.verified.cs index c2d95df..b20b414 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAG.SP_INPC_CFP#WhenAnyDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAG.SP_INPC_CFP#WhenAnyDispatch.g.verified.cs @@ -19,14 +19,14 @@ internal static partial class __ReactiveUIGeneratedBindings [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (callerLineNumber == 55 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) + if (callerLineNumber == 45 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) { - return __WhenAny_00002E2F49F125B1(objectToMonitor, selector); + return __WhenAny_00002E2F49F1247B(objectToMonitor, selector); } throw new global::System.InvalidOperationException("No generated WhenAny dispatch matched. Ensure the expression is an inline lambda for compile-time optimization."); } - private static global::System.IObservable __WhenAny_00002E2F49F125B1(global::SharedScenarios.WhenAny.SinglePropertyINPC.MyViewModel obj, global::System.Func, string> selector) + private static global::System.IObservable __WhenAny_00002E2F49F1247B(global::SharedScenarios.WhenAny.SinglePropertyINPC.MyViewModel obj, global::System.Func, string> selector) { var __propObs0 = new global::ReactiveUI.Binding.Observables.PropertyObservable( obj, diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.2O_DC_CL#WhenAnyObservableDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.2O_DC_CL#WhenAnyObservableDispatch.g.verified.cs index 2b1bd68..7085b69 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.2O_DC_CL#WhenAnyObservableDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.2O_DC_CL#WhenAnyObservableDispatch.g.verified.cs @@ -27,12 +27,12 @@ internal static partial class __ReactiveUIGeneratedBindings if (obs1Expression == "x => x.Child.Count" && obs2Expression == "x => x.Child.Message") { - return __WhenAnyObservable_7FFFF799BE875BE9(objectToMonitor, selector); + return __WhenAnyObservable_7FFFF799BE87597D(objectToMonitor, selector); } throw new global::System.InvalidOperationException("No generated WhenAnyObservable dispatch matched. This indicates a source generator caching issue."); } - private static global::System.IObservable __WhenAnyObservable_7FFFF799BE875BE9(global::SharedScenarios.WhenAnyObservable.DeepObservableCombineLatest.ParentViewModel obj, global::System.Func selector) + private static global::System.IObservable __WhenAnyObservable_7FFFF799BE87597D(global::SharedScenarios.WhenAnyObservable.DeepObservableCombineLatest.ParentViewModel obj, global::System.Func selector) { var __obsProperty0_s0 = (global::System.IObservable)new global::ReactiveUI.Binding.Observables.PropertyObservable( obj, diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.2O_DC_Merge#WhenAnyObservableDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.2O_DC_Merge#WhenAnyObservableDispatch.g.verified.cs index 7d4cd46..6144a49 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.2O_DC_Merge#WhenAnyObservableDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.2O_DC_Merge#WhenAnyObservableDispatch.g.verified.cs @@ -26,12 +26,12 @@ internal static partial class __ReactiveUIGeneratedBindings if (obs1Expression == "x => x.Child.Command1" && obs2Expression == "x => x.Child.Command2") { - return __WhenAnyObservable_000031E1E650E5C2(objectToMonitor); + return __WhenAnyObservable_000031E1E650E356(objectToMonitor); } throw new global::System.InvalidOperationException("No generated WhenAnyObservable dispatch matched. This indicates a source generator caching issue."); } - private static global::System.IObservable __WhenAnyObservable_000031E1E650E5C2(global::SharedScenarios.WhenAnyObservable.DeepObservableMerge.ParentViewModel obj) + private static global::System.IObservable __WhenAnyObservable_000031E1E650E356(global::SharedScenarios.WhenAnyObservable.DeepObservableMerge.ParentViewModel obj) { var __obsProperty0_s0 = (global::System.IObservable)new global::ReactiveUI.Binding.Observables.PropertyObservable( obj, diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.2O_Merge#WhenAnyObservableDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.2O_Merge#WhenAnyObservableDispatch.g.verified.cs index 1c78752..9232a9f 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.2O_Merge#WhenAnyObservableDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.2O_Merge#WhenAnyObservableDispatch.g.verified.cs @@ -26,12 +26,12 @@ internal static partial class __ReactiveUIGeneratedBindings if (obs1Expression == "x => x.Command1" && obs2Expression == "x => x.Command2") { - return __WhenAnyObservable_000004E8406EC233(objectToMonitor); + return __WhenAnyObservable_000004E8406EC081(objectToMonitor); } throw new global::System.InvalidOperationException("No generated WhenAnyObservable dispatch matched. This indicates a source generator caching issue."); } - private static global::System.IObservable __WhenAnyObservable_000004E8406EC233(global::SharedScenarios.WhenAnyObservable.TwoObservablesMerge.MyViewModel obj) + private static global::System.IObservable __WhenAnyObservable_000004E8406EC081(global::SharedScenarios.WhenAnyObservable.TwoObservablesMerge.MyViewModel obj) { var __obsProperty0 = new global::ReactiveUI.Binding.Observables.PropertyObservable>( obj, diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.2O_WS#WhenAnyObservableDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.2O_WS#WhenAnyObservableDispatch.g.verified.cs index 6f2e9b2..5983585 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.2O_WS#WhenAnyObservableDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.2O_WS#WhenAnyObservableDispatch.g.verified.cs @@ -27,12 +27,12 @@ internal static partial class __ReactiveUIGeneratedBindings if (obs1Expression == "x => x.Count" && obs2Expression == "x => x.Message") { - return __WhenAnyObservable_7FFFE3651E3C4253(objectToMonitor, selector); + return __WhenAnyObservable_7FFFE3651E3C40A1(objectToMonitor, selector); } throw new global::System.InvalidOperationException("No generated WhenAnyObservable dispatch matched. This indicates a source generator caching issue."); } - private static global::System.IObservable __WhenAnyObservable_7FFFE3651E3C4253(global::SharedScenarios.WhenAnyObservable.TwoObservablesWithSelector.MyViewModel obj, global::System.Func selector) + private static global::System.IObservable __WhenAnyObservable_7FFFE3651E3C40A1(global::SharedScenarios.WhenAnyObservable.TwoObservablesWithSelector.MyViewModel obj, global::System.Func selector) { var __obsProperty0 = new global::ReactiveUI.Binding.Observables.PropertyObservable>( obj, diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.MI_STS#WhenAnyObservableDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.MI_STS#WhenAnyObservableDispatch.g.verified.cs index a71b486..b948c61 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.MI_STS#WhenAnyObservableDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.MI_STS#WhenAnyObservableDispatch.g.verified.cs @@ -23,16 +23,16 @@ internal static partial class __ReactiveUIGeneratedBindings if (obs1Expression == "x => x.Command1") { - return __WhenAnyObservable_7FFFC6DF44F5655E(objectToMonitor); + return __WhenAnyObservable_7FFFC6DF44F563AC(objectToMonitor); } else if (obs1Expression == "x => x.Command2") { - return __WhenAnyObservable_7FFFC6DF47F56A17(objectToMonitor); + return __WhenAnyObservable_7FFFC6DF47F56865(objectToMonitor); } throw new global::System.InvalidOperationException("No generated WhenAnyObservable dispatch matched. This indicates a source generator caching issue."); } - private static global::System.IObservable __WhenAnyObservable_7FFFC6DF44F5655E(global::SharedScenarios.WhenAnyObservable.MultipleInvocationsSameType.MyViewModel obj) + private static global::System.IObservable __WhenAnyObservable_7FFFC6DF44F563AC(global::SharedScenarios.WhenAnyObservable.MultipleInvocationsSameType.MyViewModel obj) { var __obsProperty = new global::ReactiveUI.Binding.Observables.PropertyObservable>( obj, @@ -45,7 +45,7 @@ internal static partial class __ReactiveUIGeneratedBindings __obs => __obs ?? (global::System.IObservable)global::ReactiveUI.Binding.Observables.EmptyObservable.Instance)); } - private static global::System.IObservable __WhenAnyObservable_7FFFC6DF47F56A17(global::SharedScenarios.WhenAnyObservable.MultipleInvocationsSameType.MyViewModel obj) + private static global::System.IObservable __WhenAnyObservable_7FFFC6DF47F56865(global::SharedScenarios.WhenAnyObservable.MultipleInvocationsSameType.MyViewModel obj) { var __obsProperty = new global::ReactiveUI.Binding.Observables.PropertyObservable>( obj, diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.SingleObservable#WhenAnyObservableDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.SingleObservable#WhenAnyObservableDispatch.g.verified.cs index 5152f2c..50edfce 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.SingleObservable#WhenAnyObservableDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.SingleObservable#WhenAnyObservableDispatch.g.verified.cs @@ -23,12 +23,12 @@ internal static partial class __ReactiveUIGeneratedBindings if (obs1Expression == "x => x.MyCommand") { - return __WhenAnyObservable_7FFFCD977933883E(objectToMonitor); + return __WhenAnyObservable_7FFFCD9779338708(objectToMonitor); } throw new global::System.InvalidOperationException("No generated WhenAnyObservable dispatch matched. This indicates a source generator caching issue."); } - private static global::System.IObservable __WhenAnyObservable_7FFFCD977933883E(global::SharedScenarios.WhenAnyObservable.SingleObservable.MyViewModel obj) + private static global::System.IObservable __WhenAnyObservable_7FFFCD9779338708(global::SharedScenarios.WhenAnyObservable.SingleObservable.MyViewModel obj) { var __obsProperty = new global::ReactiveUI.Binding.Observables.PropertyObservable>( obj, diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.SingleObservable_CFP#WhenAnyObservableDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.SingleObservable_CFP#WhenAnyObservableDispatch.g.verified.cs index 01ec32d..4d546a4 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.SingleObservable_CFP#WhenAnyObservableDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.SingleObservable_CFP#WhenAnyObservableDispatch.g.verified.cs @@ -18,14 +18,14 @@ internal static partial class __ReactiveUIGeneratedBindings [global::System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "", [global::System.Runtime.CompilerServices.CallerLineNumber] int callerLineNumber = 0) { - if (callerLineNumber == 55 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) + if (callerLineNumber == 45 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) { - return __WhenAnyObservable_7FFFCD977933883E(objectToMonitor); + return __WhenAnyObservable_7FFFCD9779338708(objectToMonitor); } throw new global::System.InvalidOperationException("No generated WhenAnyObservable dispatch matched. This indicates a source generator caching issue."); } - private static global::System.IObservable __WhenAnyObservable_7FFFCD977933883E(global::SharedScenarios.WhenAnyObservable.SingleObservable.MyViewModel obj) + private static global::System.IObservable __WhenAnyObservable_7FFFCD9779338708(global::SharedScenarios.WhenAnyObservable.SingleObservable.MyViewModel obj) { var __obsProperty = new global::ReactiveUI.Binding.Observables.PropertyObservable>( obj, diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.SingleObservable_DC#WhenAnyObservableDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.SingleObservable_DC#WhenAnyObservableDispatch.g.verified.cs index b76695c..5fff039 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.SingleObservable_DC#WhenAnyObservableDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAOG.SingleObservable_DC#WhenAnyObservableDispatch.g.verified.cs @@ -23,12 +23,12 @@ internal static partial class __ReactiveUIGeneratedBindings if (obs1Expression == "x => x.Child.MyCommand") { - return __WhenAnyObservable_7FFFD9447DB2EF6A(objectToMonitor); + return __WhenAnyObservable_7FFFD9447DB2ED7A(objectToMonitor); } throw new global::System.InvalidOperationException("No generated WhenAnyObservable dispatch matched. This indicates a source generator caching issue."); } - private static global::System.IObservable __WhenAnyObservable_7FFFD9447DB2EF6A(global::SharedScenarios.WhenAnyObservable.DeepObservableSwitch.ParentViewModel obj) + private static global::System.IObservable __WhenAnyObservable_7FFFD9447DB2ED7A(global::SharedScenarios.WhenAnyObservable.DeepObservableSwitch.ParentViewModel obj) { var __obsProperty_s0 = (global::System.IObservable)new global::ReactiveUI.Binding.Observables.PropertyObservable( obj, diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAVG.SP_INPC_CFP#WhenAnyValueDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAVG.SP_INPC_CFP#WhenAnyValueDispatch.g.verified.cs index 3655ca4..6f251a7 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAVG.SP_INPC_CFP#WhenAnyValueDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WAVG.SP_INPC_CFP#WhenAnyValueDispatch.g.verified.cs @@ -24,7 +24,7 @@ internal static partial class __ReactiveUIGeneratedBindings return global::ReactiveUI.Binding.Fallback.RuntimeObservationFallback.WhenAnyValue(objectToMonitor, property1); } - if (callerLineNumber == 55 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) + if (callerLineNumber == 45 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) { return __WhenAnyValue_0000263492582AFF(objectToMonitor); } diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WCG.SP_INPC_CFP#WhenChangedDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WCG.SP_INPC_CFP#WhenChangedDispatch.g.verified.cs index 27abcdc..423dcd2 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WCG.SP_INPC_CFP#WhenChangedDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WCG.SP_INPC_CFP#WhenChangedDispatch.g.verified.cs @@ -24,7 +24,7 @@ internal static partial class __ReactiveUIGeneratedBindings return global::ReactiveUI.Binding.Fallback.RuntimeObservationFallback.WhenChanged(objectToMonitor, property1); } - if (callerLineNumber == 55 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) + if (callerLineNumber == 45 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) { return __WhenChanged_7FFFD2E8D6FC818E(objectToMonitor); } diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WCnG.4LDC_CFP#WhenChangingDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WCnG.4LDC_CFP#WhenChangingDispatch.g.verified.cs index da19b7d..9907d82 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WCnG.4LDC_CFP#WhenChangingDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WCnG.4LDC_CFP#WhenChangingDispatch.g.verified.cs @@ -24,7 +24,7 @@ internal static partial class __ReactiveUIGeneratedBindings return global::ReactiveUI.Binding.Fallback.RuntimeObservationFallback.WhenChanging(objectToMonitor, property1); } - if (callerLineNumber == 167 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) + if (callerLineNumber == 139 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) { return __WhenChanging_00001C315F48E7DF(objectToMonitor); } diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WCnG.DPC_CFP#WhenChangingDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WCnG.DPC_CFP#WhenChangingDispatch.g.verified.cs index 09331d0..8a5eb24 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WCnG.DPC_CFP#WhenChangingDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WCnG.DPC_CFP#WhenChangingDispatch.g.verified.cs @@ -24,7 +24,7 @@ internal static partial class __ReactiveUIGeneratedBindings return global::ReactiveUI.Binding.Fallback.RuntimeObservationFallback.WhenChanging(objectToMonitor, property1); } - if (callerLineNumber == 95 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) + if (callerLineNumber == 79 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) { return __WhenChanging_7FFFF85E7720B498(objectToMonitor); } diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WCnG.MP_2P_CFP#WhenChangingDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WCnG.MP_2P_CFP#WhenChangingDispatch.g.verified.cs index 539a187..4374f0f 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WCnG.MP_2P_CFP#WhenChangingDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WCnG.MP_2P_CFP#WhenChangingDispatch.g.verified.cs @@ -25,7 +25,7 @@ internal static partial class __ReactiveUIGeneratedBindings return global::ReactiveUI.Binding.Fallback.RuntimeObservationFallback.WhenChanging(objectToMonitor, property1, property2); } - if (callerLineNumber == 83 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) + if (callerLineNumber == 69 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) { return __WhenChanging_000011A95039C09F(objectToMonitor); } diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WCnG.SP_INPC_CFP#WhenChangingDispatch.g.verified.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WCnG.SP_INPC_CFP#WhenChangingDispatch.g.verified.cs index fbda4cf..68d0c26 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WCnG.SP_INPC_CFP#WhenChangingDispatch.g.verified.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WCnG.SP_INPC_CFP#WhenChangingDispatch.g.verified.cs @@ -24,7 +24,7 @@ internal static partial class __ReactiveUIGeneratedBindings return global::ReactiveUI.Binding.Fallback.RuntimeObservationFallback.WhenChanging(objectToMonitor, property1); } - if (callerLineNumber == 59 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) + if (callerLineNumber == 49 && callerFilePath.EndsWith("", global::System.StringComparison.OrdinalIgnoreCase)) { return __WhenChanging_7FFFD2B6A9CCF5C7(objectToMonitor); } diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WhenAnyGeneratorTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WhenAnyGeneratorTests.cs index 7d066a9..2ed8404 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WhenAnyGeneratorTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WhenAnyGeneratorTests.cs @@ -7,14 +7,10 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests; -/// -/// Snapshot tests for WhenAny (IObservedChange-wrapping) invocation generation. -/// +/// Snapshot tests for WhenAny (IObservedChange-wrapping) invocation generation. public class WhenAnyGeneratorTests { - /// - /// Verifies WhenAny with a single property on an INPC class. - /// + /// Verifies WhenAny with a single property on an INPC class. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_INPC() @@ -26,9 +22,7 @@ public async Task SingleProperty_INPC() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenAny with two properties and a selector combining IObservedChange values. - /// + /// Verifies WhenAny with two properties and a selector combining IObservedChange values. /// A task representing the asynchronous test operation. [Test] public async Task MultiProperty_TwoProperties() @@ -57,9 +51,7 @@ public async Task SingleProperty_INPC_CallerFilePath() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenAny with a deep property chain (x => x.Child.Name) to cover the deep chain branch. - /// + /// Verifies WhenAny with a deep property chain (x => x.Child.Name) to cover the deep chain branch. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_DeepChain() @@ -71,9 +63,7 @@ public async Task SingleProperty_DeepChain() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenAny with multiple properties where one uses a deep chain to cover the multi-property deep chain branch. - /// + /// Verifies WhenAny with multiple properties where one uses a deep chain to cover the multi-property deep chain branch. /// A task representing the asynchronous test operation. [Test] public async Task MultiProperty_DeepChain() @@ -85,9 +75,7 @@ public async Task MultiProperty_DeepChain() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenAny with multiple invocations sharing the same type signature to cover the else-if dispatch branch. - /// + /// Verifies WhenAny with multiple invocations sharing the same type signature to cover the else-if dispatch branch. /// A task representing the asynchronous test operation. [Test] public async Task MultipleInvocations_SameTypeSignature() diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WhenAnyObservableGeneratorTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WhenAnyObservableGeneratorTests.cs index 23df412..099ce36 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WhenAnyObservableGeneratorTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WhenAnyObservableGeneratorTests.cs @@ -7,14 +7,10 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests; -/// -/// Snapshot tests for WhenAnyObservable (Switch/Merge/CombineLatest) invocation generation. -/// +/// Snapshot tests for WhenAnyObservable (Switch/Merge/CombineLatest) invocation generation. public class WhenAnyObservableGeneratorTests { - /// - /// Verifies WhenAnyObservable with a single observable property (Switch pattern). - /// + /// Verifies WhenAnyObservable with a single observable property (Switch pattern). /// A task representing the asynchronous test operation. [Test] public async Task SingleObservable() @@ -28,9 +24,7 @@ public async Task SingleObservable() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenAnyObservable with two same-type observable properties (Merge pattern). - /// + /// Verifies WhenAnyObservable with two same-type observable properties (Merge pattern). /// A task representing the asynchronous test operation. [Test] public async Task TwoObservables_Merge() @@ -44,9 +38,7 @@ public async Task TwoObservables_Merge() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenAnyObservable with two different-type observable properties and a selector (CombineLatest pattern). - /// + /// Verifies WhenAnyObservable with two different-type observable properties and a selector (CombineLatest pattern). /// A task representing the asynchronous test operation. [Test] public async Task TwoObservables_WithSelector() @@ -77,9 +69,7 @@ public async Task SingleObservable_CallerFilePath() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenAnyObservable with a deep property chain in the Switch pattern (x => x.Child.MyCommand). - /// + /// Verifies WhenAnyObservable with a deep property chain in the Switch pattern (x => x.Child.MyCommand). /// A task representing the asynchronous test operation. [Test] public async Task SingleObservable_DeepChain() @@ -93,9 +83,7 @@ public async Task SingleObservable_DeepChain() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenAnyObservable with deep property chains in a Merge pattern. - /// + /// Verifies WhenAnyObservable with deep property chains in a Merge pattern. /// A task representing the asynchronous test operation. [Test] public async Task TwoObservables_DeepChain_Merge() @@ -109,9 +97,7 @@ public async Task TwoObservables_DeepChain_Merge() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenAnyObservable with deep property chains in a CombineLatest pattern with selector. - /// + /// Verifies WhenAnyObservable with deep property chains in a CombineLatest pattern with selector. /// A task representing the asynchronous test operation. [Test] public async Task TwoObservables_DeepChain_CombineLatest() diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WhenAnyValueGeneratorTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WhenAnyValueGeneratorTests.cs index baa8f77..c658dac 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WhenAnyValueGeneratorTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WhenAnyValueGeneratorTests.cs @@ -7,14 +7,10 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests; -/// -/// Snapshot tests for WhenAnyValue (ReactiveUI-compatible) invocation generation. -/// +/// Snapshot tests for WhenAnyValue (ReactiveUI-compatible) invocation generation. public class WhenAnyValueGeneratorTests { - /// - /// Verifies WhenAnyValue with a single property on an INPC class. - /// + /// Verifies WhenAnyValue with a single property on an INPC class. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_INPC() @@ -26,9 +22,7 @@ public async Task SingleProperty_INPC() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenAnyValue on a ReactiveObject-based class. - /// + /// Verifies WhenAnyValue on a ReactiveObject-based class. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_ReactiveObject() @@ -40,9 +34,7 @@ public async Task SingleProperty_ReactiveObject() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenAnyValue with two properties returns a tuple. - /// + /// Verifies WhenAnyValue with two properties returns a tuple. /// A task representing the asynchronous test operation. [Test] public async Task MultiProperty_TwoProperties() @@ -54,9 +46,7 @@ public async Task MultiProperty_TwoProperties() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenAnyValue with three properties returns a tuple. - /// + /// Verifies WhenAnyValue with three properties returns a tuple. /// A task representing the asynchronous test operation. [Test] public async Task MultiProperty_ThreeProperties() @@ -68,9 +58,7 @@ public async Task MultiProperty_ThreeProperties() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenAnyValue with a selector function combining two properties. - /// + /// Verifies WhenAnyValue with a selector function combining two properties. /// A task representing the asynchronous test operation. [Test] public async Task MultiProperty_WithSelector() @@ -82,9 +70,7 @@ public async Task MultiProperty_WithSelector() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenAnyValue with five properties. - /// + /// Verifies WhenAnyValue with five properties. /// A task representing the asynchronous test operation. [Test] public async Task MultiProperty_FiveProperties() @@ -96,9 +82,7 @@ public async Task MultiProperty_FiveProperties() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenAnyValue with a deep property chain. - /// + /// Verifies WhenAnyValue with a deep property chain. /// A task representing the asynchronous test operation. [Test] public async Task DeepPropertyChain() @@ -110,9 +94,7 @@ public async Task DeepPropertyChain() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenAnyValue with nullable property types. - /// + /// Verifies WhenAnyValue with nullable property types. /// A task representing the asynchronous test operation. [Test] public async Task NullableProperties() @@ -124,9 +106,7 @@ public async Task NullableProperties() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenAnyValue with twelve properties (maximum standard overload). - /// + /// Verifies WhenAnyValue with twelve properties (maximum standard overload). /// A task representing the asynchronous test operation. [Test] public async Task MultiProperty_TwelveProperties() diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WhenChangedGeneratorTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WhenChangedGeneratorTests.cs index 415f68d..d7fd36f 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WhenChangedGeneratorTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WhenChangedGeneratorTests.cs @@ -7,14 +7,13 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests; -/// -/// Snapshot tests for WhenChanged (after-change) invocation generation. -/// +/// Snapshot tests for WhenChanged (after-change) invocation generation. public class WhenChangedGeneratorTests { - /// - /// Verifies that a WhenChanged invocation on an INPC class generates PropertyChanged observation. - /// + /// The WhenChangedDispatch.g.cs name these tests generate against. + private const string WhenChangedDispatchgcsName = "WhenChangedDispatch.g.cs"; + + /// Verifies that a WhenChanged invocation on an INPC class generates PropertyChanged observation. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_INPC() @@ -26,9 +25,7 @@ public async Task SingleProperty_INPC() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies that the generator produces correct output when no invocations are present. - /// + /// Verifies that the generator produces correct output when no invocations are present. /// A task representing the asynchronous test operation. [Test] public async Task NoInvocations() @@ -53,9 +50,7 @@ public class MyViewModel : INotifyPropertyChanged await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenChanged on a ReactiveObject-based class. - /// + /// Verifies WhenChanged on a ReactiveObject-based class. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_ReactiveObject() @@ -67,9 +62,7 @@ public async Task SingleProperty_ReactiveObject() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenChanged with two properties returns a tuple. - /// + /// Verifies WhenChanged with two properties returns a tuple. /// A task representing the asynchronous test operation. [Test] public async Task MultiProperty_TwoProperties() @@ -81,9 +74,7 @@ public async Task MultiProperty_TwoProperties() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenChanged with three properties returns a tuple. - /// + /// Verifies WhenChanged with three properties returns a tuple. /// A task representing the asynchronous test operation. [Test] public async Task MultiProperty_ThreeProperties() @@ -95,9 +86,7 @@ public async Task MultiProperty_ThreeProperties() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenChanged with a selector function. - /// + /// Verifies WhenChanged with a selector function. /// A task representing the asynchronous test operation. [Test] public async Task MultiProperty_WithSelector() @@ -109,9 +98,7 @@ public async Task MultiProperty_WithSelector() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenChanged with a deep property chain like x => x.Child.Name. - /// + /// Verifies WhenChanged with a deep property chain like x => x.Child.Name. /// A task representing the asynchronous test operation. [Test] public async Task DeepPropertyChain() @@ -123,9 +110,7 @@ public async Task DeepPropertyChain() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenChanged with a nullable property type. - /// + /// Verifies WhenChanged with a nullable property type. /// A task representing the asynchronous test operation. [Test] public async Task NullableProperty() @@ -137,9 +122,7 @@ public async Task NullableProperty() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenChanged with multiple ViewModels in the same compilation. - /// + /// Verifies WhenChanged with multiple ViewModels in the same compilation. /// A task representing the asynchronous test operation. [Test] public async Task MultipleViewModels() @@ -151,9 +134,7 @@ public async Task MultipleViewModels() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenChanged with an integer property type. - /// + /// Verifies WhenChanged with an integer property type. /// A task representing the asynchronous test operation. [Test] public async Task IntProperty() @@ -165,9 +146,7 @@ public async Task IntProperty() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenChanged with a 4-level deep property chain (ObjChain1 -> ObjChain2 -> ObjChain3 -> Model). - /// + /// Verifies WhenChanged with a 4-level deep property chain (ObjChain1 -> ObjChain2 -> ObjChain3 -> Model). /// A task representing the asynchronous test operation. [Test] public async Task FourLevelDeepChain() @@ -179,9 +158,7 @@ public async Task FourLevelDeepChain() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenChanged with multiple invocations on the same ViewModel. - /// + /// Verifies WhenChanged with multiple invocations on the same ViewModel. /// A task representing the asynchronous test operation. [Test] public async Task MultipleInvocations_SameViewModel() @@ -567,7 +544,7 @@ public static void Execute(MyViewModel vm) // The generator should not produce any WhenChanged dispatch code // because the method belongs to CustomExtensions, not our extension class. await result.HasNoGeneratorDiagnostics(); - await result.DoesNotHaveGeneratedSource("WhenChangedDispatch.g.cs"); + await result.DoesNotHaveGeneratedSource(WhenChangedDispatchgcsName); } /// @@ -608,7 +585,7 @@ public static void Execute(MyViewModel vm) // The generator should silently skip the identity lambda and produce no dispatch. await result.HasNoGeneratorDiagnostics(); - await result.DoesNotHaveGeneratedSource("WhenChangedDispatch.g.cs"); + await result.DoesNotHaveGeneratedSource(WhenChangedDispatchgcsName); } /// @@ -648,7 +625,7 @@ public static void Execute(MyViewModel vm) // The generator should silently skip block-body lambdas and produce no dispatch. await result.HasNoGeneratorDiagnostics(); - await result.DoesNotHaveGeneratedSource("WhenChangedDispatch.g.cs"); + await result.DoesNotHaveGeneratedSource(WhenChangedDispatchgcsName); } /// @@ -688,7 +665,7 @@ public static void Execute(MyViewModel vm) // The generator should silently skip field access lambdas and produce no dispatch. await result.HasNoGeneratorDiagnostics(); - await result.DoesNotHaveGeneratedSource("WhenChangedDispatch.g.cs"); + await result.DoesNotHaveGeneratedSource(WhenChangedDispatchgcsName); } /// @@ -726,7 +703,7 @@ public void DoSomething() // The generator should silently skip private property access and produce no dispatch. await result.HasNoGeneratorDiagnostics(); - await result.DoesNotHaveGeneratedSource("WhenChangedDispatch.g.cs"); + await result.DoesNotHaveGeneratedSource(WhenChangedDispatchgcsName); } /// @@ -763,7 +740,7 @@ public void DoSomething() // The generator should silently skip protected property access and produce no dispatch. await result.HasNoGeneratorDiagnostics(); - await result.DoesNotHaveGeneratedSource("WhenChangedDispatch.g.cs"); + await result.DoesNotHaveGeneratedSource(WhenChangedDispatchgcsName); } /// @@ -804,6 +781,6 @@ public static void Execute(MyViewModel vm) // The generator should silently skip method invocations in the lambda and produce no dispatch. await result.HasNoGeneratorDiagnostics(); - await result.DoesNotHaveGeneratedSource("WhenChangedDispatch.g.cs"); + await result.DoesNotHaveGeneratedSource(WhenChangedDispatchgcsName); } } diff --git a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WhenChangingGeneratorTests.cs b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WhenChangingGeneratorTests.cs index 621d840..5824032 100644 --- a/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WhenChangingGeneratorTests.cs +++ b/src/tests/ReactiveUI.Binding.SourceGenerators.Tests/WhenChangingGeneratorTests.cs @@ -7,14 +7,10 @@ namespace ReactiveUI.Binding.SourceGenerators.Tests; -/// -/// Snapshot tests for WhenChanging (before-change) invocation generation. -/// +/// Snapshot tests for WhenChanging (before-change) invocation generation. public class WhenChangingGeneratorTests { - /// - /// Verifies that a WhenChanging invocation on an INPC+INPChanging class generates PropertyChanging observation. - /// + /// Verifies that a WhenChanging invocation on an INPC+INPChanging class generates PropertyChanging observation. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_INPC() @@ -26,9 +22,7 @@ public async Task SingleProperty_INPC() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenChanging on a ReactiveObject (which implements both INPC and INPChanging). - /// + /// Verifies WhenChanging on a ReactiveObject (which implements both INPC and INPChanging). /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_ReactiveObject() @@ -40,9 +34,7 @@ public async Task SingleProperty_ReactiveObject() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenChanging with two properties returns a tuple. - /// + /// Verifies WhenChanging with two properties returns a tuple. /// A task representing the asynchronous test operation. [Test] public async Task MultiProperty_TwoProperties() @@ -54,9 +46,7 @@ public async Task MultiProperty_TwoProperties() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenChanging with a deep property chain. - /// + /// Verifies WhenChanging with a deep property chain. /// A task representing the asynchronous test operation. [Test] public async Task DeepPropertyChain() @@ -68,9 +58,7 @@ public async Task DeepPropertyChain() await result.HasNoGeneratorDiagnostics(); } - /// - /// Verifies WhenChanging with a selector function. - /// + /// Verifies WhenChanging with a selector function. /// A task representing the asynchronous test operation. [Test] public async Task MultiProperty_WithSelector() diff --git a/src/tests/ReactiveUI.Binding.Tests/AssemblySetup.cs b/src/tests/ReactiveUI.Binding.Tests/AssemblySetup.cs index 7bae4c7..af34bf8 100644 --- a/src/tests/ReactiveUI.Binding.Tests/AssemblySetup.cs +++ b/src/tests/ReactiveUI.Binding.Tests/AssemblySetup.cs @@ -8,20 +8,16 @@ namespace ReactiveUI.Binding.Tests; -/// -/// Assembly-level setup for the test assembly. -/// +/// Assembly-level setup for the test assembly. public static class AssemblySetup { - /// - /// Initializes the test assembly by configuring the service locator. - /// + /// Initializes the test assembly by configuring the service locator. [Before(Assembly)] public static void Initialize() { RxBindingBuilder.ResetForTesting(); var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - builder.WithCoreServices(); - builder.BuildApp(); + _ = builder.WithCoreServices(); + _ = builder.BuildApp(); } } diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/BindingTypeConverterDispatchTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/BindingTypeConverterDispatchTests.cs index 8a05256..0ca6f19 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/BindingTypeConverterDispatchTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/BindingTypeConverterDispatchTests.cs @@ -6,24 +6,19 @@ namespace ReactiveUI.Binding.Tests.Bindings; -/// -/// Unit tests for . -/// +/// Unit tests for . public class BindingTypeConverterDispatchTests { - /// - /// Integer value produced by the stub converter in dispatch tests. - /// + /// The value the stub fallback converter returns. + private const string FallbackResult = "fallback"; + + /// Integer value produced by the stub converter in dispatch tests. private const int ConvertedInteger = 42; - /// - /// Double value produced by the stub converter in dispatch tests. - /// + /// Double value produced by the stub converter in dispatch tests. private const double ConvertedDouble = 3.14; - /// - /// Verifies that TryConvert returns true for an exact type match. - /// + /// Verifies that TryConvert returns true for an exact type match. /// A representing the asynchronous unit test. [Test] public async Task TryConvert_ExactTypeMatch_ReturnsTrue() @@ -31,7 +26,7 @@ public async Task TryConvert_ExactTypeMatch_ReturnsTrue() var converter = new StubBindingTypeConverter( typeof(string), typeof(int), - (from, _) => (true, int.Parse((string)from!))); + static (from, _) => (true, int.Parse((string)from!))); var success = BindingTypeConverterDispatch.TryConvert(converter, "42", typeof(int), null, out var result); @@ -39,9 +34,7 @@ public async Task TryConvert_ExactTypeMatch_ReturnsTrue() await Assert.That(result).IsEqualTo(ConvertedInteger); } - /// - /// Verifies that TryConvert returns false when the source type does not match. - /// + /// Verifies that TryConvert returns false when the source type does not match. /// A representing the asynchronous unit test. [Test] public async Task TryConvert_SourceTypeMismatch_ReturnsFalse() @@ -49,7 +42,7 @@ public async Task TryConvert_SourceTypeMismatch_ReturnsFalse() var converter = new StubBindingTypeConverter( typeof(string), typeof(int), - (_, _) => (true, 42)); + static (_, _) => (true, ConvertedInteger)); var success = BindingTypeConverterDispatch.TryConvert(converter, true, typeof(int), null, out var result); @@ -57,9 +50,7 @@ public async Task TryConvert_SourceTypeMismatch_ReturnsFalse() await Assert.That(result).IsNull(); } - /// - /// Verifies that TryConvert returns false when the target type does not match. - /// + /// Verifies that TryConvert returns false when the target type does not match. /// A representing the asynchronous unit test. [Test] public async Task TryConvert_TargetTypeMismatch_ReturnsFalse() @@ -67,7 +58,7 @@ public async Task TryConvert_TargetTypeMismatch_ReturnsFalse() var converter = new StubBindingTypeConverter( typeof(string), typeof(int), - (_, _) => (true, 42)); + static (_, _) => (true, ConvertedInteger)); var success = BindingTypeConverterDispatch.TryConvert(converter, "42", typeof(bool), null, out var result); @@ -75,9 +66,7 @@ public async Task TryConvert_TargetTypeMismatch_ReturnsFalse() await Assert.That(result).IsNull(); } - /// - /// Verifies that TryConvert handles nullable target types correctly. - /// + /// Verifies that TryConvert handles nullable target types correctly. /// A representing the asynchronous unit test. [Test] public async Task TryConvert_NullableTargetType_ReturnsTrue() @@ -85,17 +74,15 @@ public async Task TryConvert_NullableTargetType_ReturnsTrue() var converter = new StubBindingTypeConverter( typeof(double), typeof(double?), - (from, _) => (true, (double?)from)); + static (from, _) => (true, (double?)from)); - var success = BindingTypeConverterDispatch.TryConvert(converter, 3.14, typeof(double?), null, out var result); + var success = BindingTypeConverterDispatch.TryConvert(converter, ConvertedDouble, typeof(double?), null, out var result); await Assert.That(success).IsTrue(); await Assert.That(result).IsEqualTo(ConvertedDouble); } - /// - /// Verifies that TryConvert allows boxed non-nullable to nullable converter. - /// + /// Verifies that TryConvert allows boxed non-nullable to nullable converter. /// A representing the asynchronous unit test. [Test] public async Task TryConvert_BoxedNonNullableToNullableConverter_ReturnsTrue() @@ -103,17 +90,15 @@ public async Task TryConvert_BoxedNonNullableToNullableConverter_ReturnsTrue() var converter = new StubBindingTypeConverter( typeof(int?), typeof(string), - (from, _) => (true, from?.ToString() ?? "null")); + static (from, _) => (true, from?.ToString() ?? "null")); - var success = BindingTypeConverterDispatch.TryConvert(converter, 42, typeof(string), null, out var result); + var success = BindingTypeConverterDispatch.TryConvert(converter, ConvertedInteger, typeof(string), null, out var result); await Assert.That(success).IsTrue(); await Assert.That(result).IsEqualTo("42"); } - /// - /// Verifies that TryConvert returns false for null input with non-nullable FromType. - /// + /// Verifies that TryConvert returns false for null input with non-nullable FromType. /// A representing the asynchronous unit test. [Test] public async Task TryConvert_NullInputWithNonNullableFromType_ReturnsFalse() @@ -121,7 +106,7 @@ public async Task TryConvert_NullInputWithNonNullableFromType_ReturnsFalse() var converter = new StubBindingTypeConverter( typeof(int), typeof(string), - (_, _) => (true, "42")); + static (_, _) => (true, "42")); var success = BindingTypeConverterDispatch.TryConvert(converter, null, typeof(string), null, out var result); @@ -129,9 +114,7 @@ public async Task TryConvert_NullInputWithNonNullableFromType_ReturnsFalse() await Assert.That(result).IsNull(); } - /// - /// Verifies that TryConvert passes the conversion hint correctly. - /// + /// Verifies that TryConvert passes the conversion hint correctly. /// A representing the asynchronous unit test. [Test] public async Task TryConvert_PassesConversionHint() @@ -140,7 +123,7 @@ public async Task TryConvert_PassesConversionHint() var converter = new StubBindingTypeConverter( typeof(string), typeof(string), - (_, hint) => (true, hint)); + static (_, hint) => (true, hint)); var success = BindingTypeConverterDispatch.TryConvert(converter, "input", typeof(string), hintValue, out var result); @@ -149,20 +132,18 @@ public async Task TryConvert_PassesConversionHint() await Assert.That(result).IsEqualTo(hintValue); } - /// - /// Verifies that TryConvertFallback succeeds. - /// + /// Verifies that TryConvertFallback succeeds. /// A representing the asynchronous unit test. [Test] public async Task TryConvertFallback_Success_ReturnsTrue() { - var converter = new StubFallbackConverter((_, _, _, _) => (true, "fallback-result")); + var converter = new StubFallbackConverter(static (_, _, _, _) => (true, "fallback-result")); var success = BindingTypeConverterDispatch.TryConvertFallback( converter, typeof(int), - 42, + ConvertedInteger, typeof(string), null, out var result); @@ -171,20 +152,18 @@ public async Task TryConvertFallback_Success_ReturnsTrue() await Assert.That(result).IsEqualTo("fallback-result"); } - /// - /// Verifies that TryConvertFallback returns false when the result is null. - /// + /// Verifies that TryConvertFallback returns false when the result is null. /// A representing the asynchronous unit test. [Test] public async Task TryConvertFallback_NullResult_ReturnsFalse() { - var converter = new StubFallbackConverter((_, _, _, _) => (true, null)); + var converter = new StubFallbackConverter(static (_, _, _, _) => (true, null)); var success = BindingTypeConverterDispatch.TryConvertFallback( converter, typeof(int), - 42, + ConvertedInteger, typeof(string), null, out var result); @@ -193,20 +172,18 @@ public async Task TryConvertFallback_NullResult_ReturnsFalse() await Assert.That(result).IsNull(); } - /// - /// Verifies that TryConvertFallback returns false when the converter fails. - /// + /// Verifies that TryConvertFallback returns false when the converter fails. /// A representing the asynchronous unit test. [Test] public async Task TryConvertFallback_ConverterFails_ReturnsFalse() { - var converter = new StubFallbackConverter((_, _, _, _) => (false, null)); + var converter = new StubFallbackConverter(static (_, _, _, _) => (false, null)); var success = BindingTypeConverterDispatch.TryConvertFallback( converter, typeof(int), - 42, + ConvertedInteger, typeof(string), null, out var result); @@ -215,9 +192,7 @@ public async Task TryConvertFallback_ConverterFails_ReturnsFalse() await Assert.That(result).IsNull(); } - /// - /// Verifies that TryConvertAny routes to TryConvert for IBindingTypeConverter. - /// + /// Verifies that TryConvertAny routes to TryConvert for IBindingTypeConverter. /// A representing the asynchronous unit test. [Test] public async Task TryConvertAny_RoutesToTypedConverter() @@ -225,7 +200,7 @@ public async Task TryConvertAny_RoutesToTypedConverter() var converter = new StubBindingTypeConverter( typeof(string), typeof(int), - (_, _) => (true, 42)); + static (_, _) => (true, ConvertedInteger)); var success = BindingTypeConverterDispatch.TryConvertAny( @@ -240,36 +215,32 @@ public async Task TryConvertAny_RoutesToTypedConverter() await Assert.That(result).IsEqualTo(ConvertedInteger); } - /// - /// Verifies that TryConvertAny routes to TryConvertFallback for IBindingFallbackConverter. - /// + /// Verifies that TryConvertAny routes to TryConvertFallback for IBindingFallbackConverter. /// A representing the asynchronous unit test. [Test] public async Task TryConvertAny_RoutesToFallbackConverter() { - var converter = new StubFallbackConverter((_, _, _, _) => (true, "fallback")); + var converter = new StubFallbackConverter(static (_, _, _, _) => (true, FallbackResult)); var success = BindingTypeConverterDispatch.TryConvertAny( converter, typeof(int), - 42, + ConvertedInteger, typeof(string), null, out var result); await Assert.That(success).IsTrue(); - await Assert.That(result).IsEqualTo("fallback"); + await Assert.That(result).IsEqualTo(FallbackResult); } - /// - /// Verifies that TryConvertAny returns false for null input with fallback converter. - /// + /// Verifies that TryConvertAny returns false for null input with fallback converter. /// A representing the asynchronous unit test. [Test] public async Task TryConvertAny_NullInputWithFallback_ReturnsFalse() { - var converter = new StubFallbackConverter((_, _, _, _) => (true, "fallback")); + var converter = new StubFallbackConverter(static (_, _, _, _) => (true, FallbackResult)); var success = BindingTypeConverterDispatch.TryConvertAny( @@ -284,29 +255,25 @@ public async Task TryConvertAny_NullInputWithFallback_ReturnsFalse() await Assert.That(result).IsNull(); } - /// - /// Verifies that TryConvertAny returns false for unknown converter type. - /// + /// Verifies that TryConvertAny returns false for unknown converter type. /// A representing the asynchronous unit test. [Test] public async Task TryConvertAny_UnknownConverterType_ReturnsFalse() { var success = - BindingTypeConverterDispatch.TryConvertAny(new(), typeof(int), 42, typeof(string), null, out var result); + BindingTypeConverterDispatch.TryConvertAny(new(), typeof(int), ConvertedInteger, typeof(string), null, out var result); await Assert.That(success).IsFalse(); await Assert.That(result).IsNull(); } - /// - /// Verifies that TryConvertAny returns false for null converter. - /// + /// Verifies that TryConvertAny returns false for null converter. /// A representing the asynchronous unit test. [Test] public async Task TryConvertAny_NullConverter_ReturnsFalse() { var success = - BindingTypeConverterDispatch.TryConvertAny(null, typeof(int), 42, typeof(string), null, out var result); + BindingTypeConverterDispatch.TryConvertAny(null, typeof(int), ConvertedInteger, typeof(string), null, out var result); await Assert.That(success).IsFalse(); await Assert.That(result).IsNull(); @@ -324,7 +291,7 @@ public async Task TryConvert_NullInputWithNullableFromType_ProceedsToConvert() var converter = new StubBindingTypeConverter( typeof(int?), typeof(string), - (from, _) => (true, from?.ToString() ?? "null")); + static (from, _) => (true, from?.ToString() ?? "null")); // Pass null as `from` value. Since FromType (int?) is a nullable value type, // Nullable.GetUnderlyingType returns typeof(int), so the null check allows it through. diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/BindingTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/BindingTypeConverterTests.cs index 8bdcb2c..b390df0 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/BindingTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/BindingTypeConverterTests.cs @@ -11,15 +11,13 @@ namespace ReactiveUI.Binding.Tests.Bindings; /// public class BindingTypeConverterTests { - /// - /// Integer value parsed from the string "42" in conversion tests. - /// + /// The value fed into the converter under test. + private const double SourceValue = 123.45; + + /// Integer value parsed from the string "42" in conversion tests. private const int ParsedInteger = 42; - /// - /// Verifies that - /// returns the correct source type. - /// + /// Verifies that returns the correct source type. /// A representing the asynchronous unit test. [Test] public async Task FromType_ReturnsCorrectType() @@ -29,10 +27,7 @@ public async Task FromType_ReturnsCorrectType() await Assert.That(converter.FromType).IsEqualTo(typeof(string)); } - /// - /// Verifies that - /// returns the correct target type. - /// + /// Verifies that returns the correct target type. /// A representing the asynchronous unit test. [Test] public async Task ToType_ReturnsCorrectType() @@ -42,26 +37,20 @@ public async Task ToType_ReturnsCorrectType() await Assert.That(converter.ToType).IsEqualTo(typeof(int)); } - /// - /// Verifies that - /// returns false when the input type doesn't match TFrom. - /// + /// Verifies that returns false when the input type doesn't match TFrom. /// A representing the asynchronous unit test. [Test] public async Task TryConvertTyped_TypeMismatch_ReturnsFalse() { var converter = new TestConverter(); - var result = converter.TryConvertTyped(123.45, null, out var output); + var result = converter.TryConvertTyped(SourceValue, null, out var output); await Assert.That(result).IsFalse(); await Assert.That(output).IsNull(); } - /// - /// Verifies that - /// successfully converts a valid input. - /// + /// Verifies that successfully converts a valid input. /// A representing the asynchronous unit test. [Test] public async Task TryConvertTyped_ValidInput_Succeeds() @@ -74,10 +63,7 @@ public async Task TryConvertTyped_ValidInput_Succeeds() await Assert.That(output).IsEqualTo(ParsedInteger); } - /// - /// Verifies that - /// returns false when conversion fails. - /// + /// Verifies that returns false when conversion fails. /// A representing the asynchronous unit test. [Test] public async Task TryConvertTyped_ConversionFails_ReturnsFalse() @@ -90,10 +76,7 @@ public async Task TryConvertTyped_ConversionFails_ReturnsFalse() await Assert.That(output).IsNull(); } - /// - /// Verifies that - /// handles null input correctly when TFrom is a reference type. - /// + /// Verifies that handles null input correctly when TFrom is a reference type. /// A representing the asynchronous unit test. [Test] public async Task TryConvertTyped_NullInputWithReferenceTypeSource_HandlesCorrectly() @@ -106,10 +89,7 @@ public async Task TryConvertTyped_NullInputWithReferenceTypeSource_HandlesCorrec await Assert.That(output).IsNull(); } - /// - /// Verifies that - /// returns false when input is null and TFrom is a non-nullable value type. - /// + /// Verifies that returns false when input is null and TFrom is a non-nullable value type. /// A representing the asynchronous unit test. [Test] public async Task TryConvertTyped_NullInputWithValueTypeSource_ReturnsFalse() @@ -122,10 +102,7 @@ public async Task TryConvertTyped_NullInputWithValueTypeSource_ReturnsFalse() await Assert.That(output).IsNull(); } - /// - /// Verifies that - /// succeeds when converting from nullable source type with null input. - /// + /// Verifies that succeeds when converting from nullable source type with null input. /// A representing the asynchronous unit test. [Test] public async Task TryConvertTyped_NullInputWithNullableSource_Succeeds() @@ -138,10 +115,7 @@ public async Task TryConvertTyped_NullInputWithNullableSource_Succeeds() await Assert.That(output).IsEqualTo("null"); } - /// - /// Verifies that - /// handles the case when TryConvert returns null for a non-nullable target type. - /// + /// Verifies that handles the case when TryConvert returns null for a non-nullable target type. /// A representing the asynchronous unit test. [Test] public async Task TryConvertTyped_NullResultWithNonNullableTarget_ReturnsFalse() @@ -154,10 +128,7 @@ public async Task TryConvertTyped_NullResultWithNonNullableTarget_ReturnsFalse() await Assert.That(output).IsNull(); } - /// - /// Verifies that - /// succeeds when TryConvert returns null for a nullable target type. - /// + /// Verifies that succeeds when TryConvert returns null for a nullable target type. /// A representing the asynchronous unit test. [Test] public async Task TryConvertTyped_NullResultWithNullableTarget_Succeeds() @@ -170,10 +141,7 @@ public async Task TryConvertTyped_NullResultWithNullableTarget_Succeeds() await Assert.That(output).IsNull(); } - /// - /// Verifies that - /// handles null input when source is nullable and conversion returns false. - /// + /// Verifies that handles null input when source is nullable and conversion returns false. /// A representing the asynchronous unit test. [Test] public async Task TryConvertTyped_NullInputWithNullableSourceButConversionFails_ReturnsFalse() @@ -186,9 +154,7 @@ public async Task TryConvertTyped_NullInputWithNullableSourceButConversionFails_ await Assert.That(output).IsNull(); } - /// - /// Test converter from string to int. - /// + /// Test converter from string to int. private sealed class TestConverter : BindingTypeConverter { /// @@ -207,9 +173,7 @@ public override bool TryConvert(string? from, object? conversionHint, [NotNullWh } } - /// - /// Test converter from int to string (value type to reference type). - /// + /// Test converter from int to string (value type to reference type). private sealed class ValueTypeConverter : BindingTypeConverter { /// @@ -223,9 +187,7 @@ public override bool TryConvert(int from, object? conversionHint, [NotNullWhen(t } } - /// - /// Test converter from int? to string that handles null input. - /// + /// Test converter from int? to string that handles null input. private sealed class NullableToStringConverter : BindingTypeConverter { /// @@ -239,9 +201,7 @@ public override bool TryConvert(int? from, object? conversionHint, [NotNullWhen( } } - /// - /// Test converter that fails conversion, used to test null handling for non-nullable target types. - /// + /// Test converter that fails conversion, used to test null handling for non-nullable target types. private sealed class NullReturningConverter : BindingTypeConverter { /// @@ -255,9 +215,7 @@ public override bool TryConvert(string? from, object? conversionHint, [NotNullWh } } - /// - /// Test converter from string to int? that returns null for "null" input. - /// + /// Test converter from string to int? that returns null for "null" input. private sealed class StringToNullableIntConverter : BindingTypeConverter { /// @@ -283,9 +241,7 @@ public override bool TryConvert(string? from, object? conversionHint, out int? r } } - /// - /// Test converter from int? to string that always fails conversion for null input. - /// + /// Test converter from int? to string that always fails conversion for null input. private sealed class NullableFailingConverter : BindingTypeConverter { /// diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/BindingTypeConverterTryConvertTypedTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/BindingTypeConverterTryConvertTypedTests.cs index 0ceb2e7..82983e3 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/BindingTypeConverterTryConvertTypedTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/BindingTypeConverterTryConvertTypedTests.cs @@ -4,755 +4,556 @@ namespace ReactiveUI.Binding.Tests.Bindings; -/// -/// Unit tests for -/// to ensure coverage of the base class dispatch path. -/// +/// Unit tests for to ensure coverage of the base class dispatch path. public class BindingTypeConverterTryConvertTypedTests { - /// - /// Literal used as a deliberately wrong-typed conversion input. - /// + /// Literal used as a deliberately wrong-typed conversion input. private const string WrongTypeInput = "wrong"; - /// - /// Sample byte value used for byte conversion tests. - /// + /// Sample byte value used for byte conversion tests. private const byte ByteValue = 42; - /// - /// Smaller byte value used for byte conversion tests. - /// + /// Smaller byte value used for byte conversion tests. private const byte SmallByteValue = 7; - /// - /// Sample integer value used for integer conversion tests. - /// + /// Sample integer value used for integer conversion tests. private const int IntValue = 123; - /// - /// Smaller integer value used for integer conversion tests. - /// + /// Smaller integer value used for integer conversion tests. private const int SmallIntValue = 42; - /// - /// Integer value parsed from a string in conversion tests. - /// + /// Integer value parsed from a string in conversion tests. private const int ParsedIntValue = 456; - /// - /// Sample double value used for double conversion tests. - /// + /// Sample double value used for double conversion tests. private const double DoubleValue = 3.14; - /// - /// Alternate double value used for double conversion tests. - /// + /// Alternate double value used for double conversion tests. private const double EulerDoubleValue = 2.718; - /// - /// Sample long value used for long conversion tests. - /// + /// Sample long value used for long conversion tests. private const long LongValue = 9_876_543_210L; - /// - /// Sample short value used for short conversion tests. - /// + /// Sample short value used for short conversion tests. private const short ShortValue = 321; - /// - /// Sample single-precision value used for float conversion tests. - /// - private const float SingleValue = 1.5f; + /// Sample single-precision value used for float conversion tests. + private const float SingleValue = 1.5F; - /// - /// Sample decimal value used for decimal conversion tests. - /// - private const decimal DecimalValue = 99.99m; + /// Sample decimal value used for decimal conversion tests. + private const decimal DecimalValue = 99.99M; // =================================================================== // Non-nullable to String converters // =================================================================== - - /// - /// Verifies ByteToStringTypeConverter converts a byte value to its string representation. - /// + /// Verifies ByteToStringTypeConverter converts a byte value to its string representation. /// A task representing the asynchronous test operation. [Test] - public async Task ByteToString_Success() => - await AssertConverterSuccess(new ByteToStringTypeConverter(), (byte)ByteValue, "42"); + public Task ByteToString_Success() => + AssertConverterSuccess(new ByteToStringTypeConverter(), ByteValue, "42"); - /// - /// Verifies ByteToStringTypeConverter fails when given a wrong type. - /// + /// Verifies ByteToStringTypeConverter fails when given a wrong type. /// A task representing the asynchronous test operation. [Test] - public async Task ByteToString_Failure_WrongType() => - await AssertConverterFailure(new ByteToStringTypeConverter(), WrongTypeInput); + public Task ByteToString_Failure_WrongType() => + AssertConverterFailure(new ByteToStringTypeConverter(), WrongTypeInput); - /// - /// Verifies ByteToStringTypeConverter fails when given null. - /// + /// Verifies ByteToStringTypeConverter fails when given null. /// A task representing the asynchronous test operation. [Test] - public async Task ByteToString_Failure_Null() => - await AssertConverterFailure(new ByteToStringTypeConverter(), null); + public Task ByteToString_Failure_Null() => + AssertConverterFailure(new ByteToStringTypeConverter(), null); - /// - /// Verifies IntegerToStringTypeConverter converts an int value to its string representation. - /// + /// Verifies IntegerToStringTypeConverter converts an int value to its string representation. /// A task representing the asynchronous test operation. [Test] - public async Task IntegerToString_Success() => - await AssertConverterSuccess(new IntegerToStringTypeConverter(), IntValue, "123"); + public Task IntegerToString_Success() => + AssertConverterSuccess(new IntegerToStringTypeConverter(), IntValue, "123"); - /// - /// Verifies IntegerToStringTypeConverter fails when given a wrong type. - /// + /// Verifies IntegerToStringTypeConverter fails when given a wrong type. /// A task representing the asynchronous test operation. [Test] - public async Task IntegerToString_Failure_WrongType() => - await AssertConverterFailure(new IntegerToStringTypeConverter(), WrongTypeInput); + public Task IntegerToString_Failure_WrongType() => + AssertConverterFailure(new IntegerToStringTypeConverter(), WrongTypeInput); - /// - /// Verifies IntegerToStringTypeConverter fails when given null. - /// + /// Verifies IntegerToStringTypeConverter fails when given null. /// A task representing the asynchronous test operation. [Test] - public async Task IntegerToString_Failure_Null() => - await AssertConverterFailure(new IntegerToStringTypeConverter(), null); + public Task IntegerToString_Failure_Null() => + AssertConverterFailure(new IntegerToStringTypeConverter(), null); - /// - /// Verifies StringToIntegerTypeConverter converts a string to an int. - /// + /// Verifies StringToIntegerTypeConverter converts a string to an int. /// A task representing the asynchronous test operation. [Test] - public async Task StringToInteger_Success() => - await AssertConverterSuccess(new StringToIntegerTypeConverter(), "456", ParsedIntValue); + public Task StringToInteger_Success() => + AssertConverterSuccess(new StringToIntegerTypeConverter(), "456", ParsedIntValue); - /// - /// Verifies BooleanToStringTypeConverter converts true to "True". - /// + /// Verifies BooleanToStringTypeConverter converts true to "True". /// A task representing the asynchronous test operation. [Test] - public async Task BooleanToString_Success() => - await AssertConverterSuccess(new BooleanToStringTypeConverter(), true, "True"); + public Task BooleanToString_Success() => + AssertConverterSuccess(new BooleanToStringTypeConverter(), true, "True"); - /// - /// Verifies DoubleToStringTypeConverter converts a double to its string representation. - /// + /// Verifies DoubleToStringTypeConverter converts a double to its string representation. /// A task representing the asynchronous test operation. [Test] - public async Task DoubleToString_Success() => - await AssertConverterSuccess(new DoubleToStringTypeConverter(), DoubleValue, DoubleValue.ToString(System.Globalization.CultureInfo.CurrentCulture)); + public Task DoubleToString_Success() => + AssertConverterSuccess(new DoubleToStringTypeConverter(), DoubleValue, DoubleValue.ToString(System.Globalization.CultureInfo.CurrentCulture)); - /// - /// Verifies DoubleToStringTypeConverter fails when given a wrong type. - /// + /// Verifies DoubleToStringTypeConverter fails when given a wrong type. /// A task representing the asynchronous test operation. [Test] - public async Task DoubleToString_Failure_WrongType() => - await AssertConverterFailure(new DoubleToStringTypeConverter(), WrongTypeInput); + public Task DoubleToString_Failure_WrongType() => + AssertConverterFailure(new DoubleToStringTypeConverter(), WrongTypeInput); - /// - /// Verifies DoubleToStringTypeConverter fails when given null. - /// + /// Verifies DoubleToStringTypeConverter fails when given null. /// A task representing the asynchronous test operation. [Test] - public async Task DoubleToString_Failure_Null() => - await AssertConverterFailure(new DoubleToStringTypeConverter(), null); + public Task DoubleToString_Failure_Null() => + AssertConverterFailure(new DoubleToStringTypeConverter(), null); - /// - /// Verifies LongToStringTypeConverter converts a long to its string representation. - /// + /// Verifies LongToStringTypeConverter converts a long to its string representation. /// A task representing the asynchronous test operation. [Test] - public async Task LongToString_Success() => - await AssertConverterSuccess(new LongToStringTypeConverter(), LongValue, "9876543210"); + public Task LongToString_Success() => + AssertConverterSuccess(new LongToStringTypeConverter(), LongValue, "9876543210"); - /// - /// Verifies LongToStringTypeConverter fails when given a wrong type. - /// + /// Verifies LongToStringTypeConverter fails when given a wrong type. /// A task representing the asynchronous test operation. [Test] - public async Task LongToString_Failure_WrongType() => - await AssertConverterFailure(new LongToStringTypeConverter(), WrongTypeInput); + public Task LongToString_Failure_WrongType() => + AssertConverterFailure(new LongToStringTypeConverter(), WrongTypeInput); - /// - /// Verifies LongToStringTypeConverter fails when given null. - /// + /// Verifies LongToStringTypeConverter fails when given null. /// A task representing the asynchronous test operation. [Test] - public async Task LongToString_Failure_Null() => - await AssertConverterFailure(new LongToStringTypeConverter(), null); + public Task LongToString_Failure_Null() => + AssertConverterFailure(new LongToStringTypeConverter(), null); - /// - /// Verifies ShortToStringTypeConverter converts a short to its string representation. - /// + /// Verifies ShortToStringTypeConverter converts a short to its string representation. /// A task representing the asynchronous test operation. [Test] - public async Task ShortToString_Success() => - await AssertConverterSuccess(new ShortToStringTypeConverter(), (short)ShortValue, "321"); + public Task ShortToString_Success() => + AssertConverterSuccess(new ShortToStringTypeConverter(), ShortValue, "321"); - /// - /// Verifies ShortToStringTypeConverter fails when given a wrong type. - /// + /// Verifies ShortToStringTypeConverter fails when given a wrong type. /// A task representing the asynchronous test operation. [Test] - public async Task ShortToString_Failure_WrongType() => - await AssertConverterFailure(new ShortToStringTypeConverter(), WrongTypeInput); + public Task ShortToString_Failure_WrongType() => + AssertConverterFailure(new ShortToStringTypeConverter(), WrongTypeInput); - /// - /// Verifies ShortToStringTypeConverter fails when given null. - /// + /// Verifies ShortToStringTypeConverter fails when given null. /// A task representing the asynchronous test operation. [Test] - public async Task ShortToString_Failure_Null() => - await AssertConverterFailure(new ShortToStringTypeConverter(), null); + public Task ShortToString_Failure_Null() => + AssertConverterFailure(new ShortToStringTypeConverter(), null); - /// - /// Verifies SingleToStringTypeConverter converts a float to its string representation. - /// + /// Verifies SingleToStringTypeConverter converts a float to its string representation. /// A task representing the asynchronous test operation. [Test] - public async Task SingleToString_Success() => - await AssertConverterSuccess(new SingleToStringTypeConverter(), SingleValue, SingleValue.ToString(System.Globalization.CultureInfo.CurrentCulture)); + public Task SingleToString_Success() => + AssertConverterSuccess(new SingleToStringTypeConverter(), SingleValue, SingleValue.ToString(System.Globalization.CultureInfo.CurrentCulture)); - /// - /// Verifies SingleToStringTypeConverter fails when given a wrong type. - /// + /// Verifies SingleToStringTypeConverter fails when given a wrong type. /// A task representing the asynchronous test operation. [Test] - public async Task SingleToString_Failure_WrongType() => - await AssertConverterFailure(new SingleToStringTypeConverter(), WrongTypeInput); + public Task SingleToString_Failure_WrongType() => + AssertConverterFailure(new SingleToStringTypeConverter(), WrongTypeInput); - /// - /// Verifies SingleToStringTypeConverter fails when given null. - /// + /// Verifies SingleToStringTypeConverter fails when given null. /// A task representing the asynchronous test operation. [Test] - public async Task SingleToString_Failure_Null() => - await AssertConverterFailure(new SingleToStringTypeConverter(), null); + public Task SingleToString_Failure_Null() => + AssertConverterFailure(new SingleToStringTypeConverter(), null); // =================================================================== // Nullable to String converters // =================================================================== - - /// - /// Verifies NullableByteToStringTypeConverter converts a byte to its string representation. - /// + /// Verifies NullableByteToStringTypeConverter converts a byte to its string representation. /// A task representing the asynchronous test operation. [Test] - public async Task NullableByteToString_Success() => - await AssertConverterSuccess(new NullableByteToStringTypeConverter(), (byte)ByteValue, "42"); + public Task NullableByteToString_Success() => + AssertConverterSuccess(new NullableByteToStringTypeConverter(), ByteValue, "42"); - /// - /// Verifies NullableByteToStringTypeConverter fails when given a wrong type. - /// + /// Verifies NullableByteToStringTypeConverter fails when given a wrong type. /// A task representing the asynchronous test operation. [Test] - public async Task NullableByteToString_Failure_WrongType() => - await AssertConverterFailure(new NullableByteToStringTypeConverter(), WrongTypeInput); + public Task NullableByteToString_Failure_WrongType() => + AssertConverterFailure(new NullableByteToStringTypeConverter(), WrongTypeInput); - /// - /// Verifies NullableByteToStringTypeConverter succeeds when given null. - /// + /// Verifies NullableByteToStringTypeConverter succeeds when given null. /// A task representing the asynchronous test operation. [Test] - public async Task NullableByteToString_Success_Null() => - await AssertConverterSuccess(new NullableByteToStringTypeConverter(), null, null); + public Task NullableByteToString_Success_Null() => + AssertConverterSuccess(new NullableByteToStringTypeConverter(), null, null); - /// - /// Verifies NullableDecimalToStringTypeConverter converts a decimal to its string representation. - /// + /// Verifies NullableDecimalToStringTypeConverter converts a decimal to its string representation. /// A task representing the asynchronous test operation. [Test] - public async Task NullableDecimalToString_Success() => - await AssertConverterSuccess(new NullableDecimalToStringTypeConverter(), DecimalValue, DecimalValue.ToString(System.Globalization.CultureInfo.CurrentCulture)); + public Task NullableDecimalToString_Success() => + AssertConverterSuccess(new NullableDecimalToStringTypeConverter(), DecimalValue, DecimalValue.ToString(System.Globalization.CultureInfo.CurrentCulture)); - /// - /// Verifies NullableDecimalToStringTypeConverter fails when given a wrong type. - /// + /// Verifies NullableDecimalToStringTypeConverter fails when given a wrong type. /// A task representing the asynchronous test operation. [Test] - public async Task NullableDecimalToString_Failure_WrongType() => - await AssertConverterFailure(new NullableDecimalToStringTypeConverter(), WrongTypeInput); + public Task NullableDecimalToString_Failure_WrongType() => + AssertConverterFailure(new NullableDecimalToStringTypeConverter(), WrongTypeInput); - /// - /// Verifies NullableDecimalToStringTypeConverter succeeds when given null. - /// + /// Verifies NullableDecimalToStringTypeConverter succeeds when given null. /// A task representing the asynchronous test operation. [Test] - public async Task NullableDecimalToString_Success_Null() => - await AssertConverterSuccess(new NullableDecimalToStringTypeConverter(), null, null); + public Task NullableDecimalToString_Success_Null() => + AssertConverterSuccess(new NullableDecimalToStringTypeConverter(), null, null); - /// - /// Verifies NullableDoubleToStringTypeConverter converts a double to its string representation. - /// + /// Verifies NullableDoubleToStringTypeConverter converts a double to its string representation. /// A task representing the asynchronous test operation. [Test] - public async Task NullableDoubleToString_Success() => - await AssertConverterSuccess(new NullableDoubleToStringTypeConverter(), EulerDoubleValue, EulerDoubleValue.ToString(System.Globalization.CultureInfo.CurrentCulture)); + public Task NullableDoubleToString_Success() => + AssertConverterSuccess(new NullableDoubleToStringTypeConverter(), EulerDoubleValue, EulerDoubleValue.ToString(System.Globalization.CultureInfo.CurrentCulture)); - /// - /// Verifies NullableDoubleToStringTypeConverter fails when given a wrong type. - /// + /// Verifies NullableDoubleToStringTypeConverter fails when given a wrong type. /// A task representing the asynchronous test operation. [Test] - public async Task NullableDoubleToString_Failure_WrongType() => - await AssertConverterFailure(new NullableDoubleToStringTypeConverter(), WrongTypeInput); + public Task NullableDoubleToString_Failure_WrongType() => + AssertConverterFailure(new NullableDoubleToStringTypeConverter(), WrongTypeInput); - /// - /// Verifies NullableDoubleToStringTypeConverter succeeds when given null. - /// + /// Verifies NullableDoubleToStringTypeConverter succeeds when given null. /// A task representing the asynchronous test operation. [Test] - public async Task NullableDoubleToString_Success_Null() => - await AssertConverterSuccess(new NullableDoubleToStringTypeConverter(), null, null); + public Task NullableDoubleToString_Success_Null() => + AssertConverterSuccess(new NullableDoubleToStringTypeConverter(), null, null); - /// - /// Verifies NullableIntegerToStringTypeConverter converts an int to its string representation. - /// + /// Verifies NullableIntegerToStringTypeConverter converts an int to its string representation. /// A task representing the asynchronous test operation. [Test] - public async Task NullableIntegerToString_Success() => - await AssertConverterSuccess(new NullableIntegerToStringTypeConverter(), IntValue, "123"); + public Task NullableIntegerToString_Success() => + AssertConverterSuccess(new NullableIntegerToStringTypeConverter(), IntValue, "123"); - /// - /// Verifies NullableIntegerToStringTypeConverter fails when given a wrong type. - /// + /// Verifies NullableIntegerToStringTypeConverter fails when given a wrong type. /// A task representing the asynchronous test operation. [Test] - public async Task NullableIntegerToString_Failure_WrongType() => - await AssertConverterFailure(new NullableIntegerToStringTypeConverter(), WrongTypeInput); + public Task NullableIntegerToString_Failure_WrongType() => + AssertConverterFailure(new NullableIntegerToStringTypeConverter(), WrongTypeInput); - /// - /// Verifies NullableIntegerToStringTypeConverter succeeds when given null. - /// + /// Verifies NullableIntegerToStringTypeConverter succeeds when given null. /// A task representing the asynchronous test operation. [Test] - public async Task NullableIntegerToString_Success_Null() => - await AssertConverterSuccess(new NullableIntegerToStringTypeConverter(), null, null); + public Task NullableIntegerToString_Success_Null() => + AssertConverterSuccess(new NullableIntegerToStringTypeConverter(), null, null); - /// - /// Verifies NullableLongToStringTypeConverter converts a long to its string representation. - /// + /// Verifies NullableLongToStringTypeConverter converts a long to its string representation. /// A task representing the asynchronous test operation. [Test] - public async Task NullableLongToString_Success() => - await AssertConverterSuccess(new NullableLongToStringTypeConverter(), LongValue, "9876543210"); + public Task NullableLongToString_Success() => + AssertConverterSuccess(new NullableLongToStringTypeConverter(), LongValue, "9876543210"); - /// - /// Verifies NullableLongToStringTypeConverter fails when given a wrong type. - /// + /// Verifies NullableLongToStringTypeConverter fails when given a wrong type. /// A task representing the asynchronous test operation. [Test] - public async Task NullableLongToString_Failure_WrongType() => - await AssertConverterFailure(new NullableLongToStringTypeConverter(), WrongTypeInput); + public Task NullableLongToString_Failure_WrongType() => + AssertConverterFailure(new NullableLongToStringTypeConverter(), WrongTypeInput); - /// - /// Verifies NullableLongToStringTypeConverter succeeds when given null. - /// + /// Verifies NullableLongToStringTypeConverter succeeds when given null. /// A task representing the asynchronous test operation. [Test] - public async Task NullableLongToString_Success_Null() => - await AssertConverterSuccess(new NullableLongToStringTypeConverter(), null, null); + public Task NullableLongToString_Success_Null() => + AssertConverterSuccess(new NullableLongToStringTypeConverter(), null, null); - /// - /// Verifies NullableShortToStringTypeConverter converts a short to its string representation. - /// + /// Verifies NullableShortToStringTypeConverter converts a short to its string representation. /// A task representing the asynchronous test operation. [Test] - public async Task NullableShortToString_Success() => - await AssertConverterSuccess(new NullableShortToStringTypeConverter(), (short)ShortValue, "321"); + public Task NullableShortToString_Success() => + AssertConverterSuccess(new NullableShortToStringTypeConverter(), ShortValue, "321"); - /// - /// Verifies NullableShortToStringTypeConverter fails when given a wrong type. - /// + /// Verifies NullableShortToStringTypeConverter fails when given a wrong type. /// A task representing the asynchronous test operation. [Test] - public async Task NullableShortToString_Failure_WrongType() => - await AssertConverterFailure(new NullableShortToStringTypeConverter(), WrongTypeInput); + public Task NullableShortToString_Failure_WrongType() => + AssertConverterFailure(new NullableShortToStringTypeConverter(), WrongTypeInput); - /// - /// Verifies NullableShortToStringTypeConverter succeeds when given null. - /// + /// Verifies NullableShortToStringTypeConverter succeeds when given null. /// A task representing the asynchronous test operation. [Test] - public async Task NullableShortToString_Success_Null() => - await AssertConverterSuccess(new NullableShortToStringTypeConverter(), null, null); + public Task NullableShortToString_Success_Null() => + AssertConverterSuccess(new NullableShortToStringTypeConverter(), null, null); - /// - /// Verifies NullableSingleToStringTypeConverter converts a float to its string representation. - /// + /// Verifies NullableSingleToStringTypeConverter converts a float to its string representation. /// A task representing the asynchronous test operation. [Test] - public async Task NullableSingleToString_Success() => - await AssertConverterSuccess(new NullableSingleToStringTypeConverter(), SingleValue, SingleValue.ToString(System.Globalization.CultureInfo.CurrentCulture)); + public Task NullableSingleToString_Success() => + AssertConverterSuccess(new NullableSingleToStringTypeConverter(), SingleValue, SingleValue.ToString(System.Globalization.CultureInfo.CurrentCulture)); - /// - /// Verifies NullableSingleToStringTypeConverter fails when given a wrong type. - /// + /// Verifies NullableSingleToStringTypeConverter fails when given a wrong type. /// A task representing the asynchronous test operation. [Test] - public async Task NullableSingleToString_Failure_WrongType() => - await AssertConverterFailure(new NullableSingleToStringTypeConverter(), WrongTypeInput); + public Task NullableSingleToString_Failure_WrongType() => + AssertConverterFailure(new NullableSingleToStringTypeConverter(), WrongTypeInput); - /// - /// Verifies NullableSingleToStringTypeConverter succeeds when given null. - /// + /// Verifies NullableSingleToStringTypeConverter succeeds when given null. /// A task representing the asynchronous test operation. [Test] - public async Task NullableSingleToString_Success_Null() => - await AssertConverterSuccess(new NullableSingleToStringTypeConverter(), null, null); + public Task NullableSingleToString_Success_Null() => + AssertConverterSuccess(new NullableSingleToStringTypeConverter(), null, null); // =================================================================== // Value-to-Nullable converters // =================================================================== - - /// - /// Verifies DoubleToNullableDoubleTypeConverter converts a double to nullable double. - /// + /// Verifies DoubleToNullableDoubleTypeConverter converts a double to nullable double. /// A task representing the asynchronous test operation. [Test] - public async Task DoubleToNullableDouble_Success() => - await AssertConverterSuccess(new DoubleToNullableDoubleTypeConverter(), DoubleValue, (double?)DoubleValue); + public Task DoubleToNullableDouble_Success() => + AssertConverterSuccess(new DoubleToNullableDoubleTypeConverter(), DoubleValue, (double?)DoubleValue); - /// - /// Verifies DoubleToNullableDoubleTypeConverter fails when given a wrong type. - /// + /// Verifies DoubleToNullableDoubleTypeConverter fails when given a wrong type. /// A task representing the asynchronous test operation. [Test] - public async Task DoubleToNullableDouble_Failure_WrongType() => - await AssertConverterFailure(new DoubleToNullableDoubleTypeConverter(), WrongTypeInput); + public Task DoubleToNullableDouble_Failure_WrongType() => + AssertConverterFailure(new DoubleToNullableDoubleTypeConverter(), WrongTypeInput); - /// - /// Verifies DoubleToNullableDoubleTypeConverter fails when given null. - /// + /// Verifies DoubleToNullableDoubleTypeConverter fails when given null. /// A task representing the asynchronous test operation. [Test] - public async Task DoubleToNullableDouble_Failure_Null() => - await AssertConverterFailure(new DoubleToNullableDoubleTypeConverter(), null); + public Task DoubleToNullableDouble_Failure_Null() => + AssertConverterFailure(new DoubleToNullableDoubleTypeConverter(), null); - /// - /// Verifies IntegerToNullableIntegerTypeConverter converts an int to nullable int. - /// + /// Verifies IntegerToNullableIntegerTypeConverter converts an int to nullable int. /// A task representing the asynchronous test operation. [Test] - public async Task IntegerToNullableInteger_Success() => - await AssertConverterSuccess(new IntegerToNullableIntegerTypeConverter(), SmallIntValue, (int?)SmallIntValue); + public Task IntegerToNullableInteger_Success() => + AssertConverterSuccess(new IntegerToNullableIntegerTypeConverter(), SmallIntValue, (int?)SmallIntValue); - /// - /// Verifies IntegerToNullableIntegerTypeConverter fails when given a wrong type. - /// + /// Verifies IntegerToNullableIntegerTypeConverter fails when given a wrong type. /// A task representing the asynchronous test operation. [Test] - public async Task IntegerToNullableInteger_Failure_WrongType() => - await AssertConverterFailure(new IntegerToNullableIntegerTypeConverter(), WrongTypeInput); + public Task IntegerToNullableInteger_Failure_WrongType() => + AssertConverterFailure(new IntegerToNullableIntegerTypeConverter(), WrongTypeInput); - /// - /// Verifies IntegerToNullableIntegerTypeConverter fails when given null. - /// + /// Verifies IntegerToNullableIntegerTypeConverter fails when given null. /// A task representing the asynchronous test operation. [Test] - public async Task IntegerToNullableInteger_Failure_Null() => - await AssertConverterFailure(new IntegerToNullableIntegerTypeConverter(), null); + public Task IntegerToNullableInteger_Failure_Null() => + AssertConverterFailure(new IntegerToNullableIntegerTypeConverter(), null); - /// - /// Verifies ByteToNullableByteTypeConverter converts a byte to nullable byte. - /// + /// Verifies ByteToNullableByteTypeConverter converts a byte to nullable byte. /// A task representing the asynchronous test operation. [Test] - public async Task ByteToNullableByte_Success() => - await AssertConverterSuccess(new ByteToNullableByteTypeConverter(), (byte)SmallByteValue, (byte?)SmallByteValue); + public Task ByteToNullableByte_Success() => + AssertConverterSuccess(new ByteToNullableByteTypeConverter(), SmallByteValue, (byte?)SmallByteValue); - /// - /// Verifies ByteToNullableByteTypeConverter fails when given a wrong type. - /// + /// Verifies ByteToNullableByteTypeConverter fails when given a wrong type. /// A task representing the asynchronous test operation. [Test] - public async Task ByteToNullableByte_Failure_WrongType() => - await AssertConverterFailure(new ByteToNullableByteTypeConverter(), WrongTypeInput); + public Task ByteToNullableByte_Failure_WrongType() => + AssertConverterFailure(new ByteToNullableByteTypeConverter(), WrongTypeInput); - /// - /// Verifies ByteToNullableByteTypeConverter fails when given null. - /// + /// Verifies ByteToNullableByteTypeConverter fails when given null. /// A task representing the asynchronous test operation. [Test] - public async Task ByteToNullableByte_Failure_Null() => - await AssertConverterFailure(new ByteToNullableByteTypeConverter(), null); + public Task ByteToNullableByte_Failure_Null() => + AssertConverterFailure(new ByteToNullableByteTypeConverter(), null); - /// - /// Verifies LongToNullableLongTypeConverter converts a long to nullable long. - /// + /// Verifies LongToNullableLongTypeConverter converts a long to nullable long. /// A task representing the asynchronous test operation. [Test] - public async Task LongToNullableLong_Success() => - await AssertConverterSuccess(new LongToNullableLongTypeConverter(), LongValue, (long?)LongValue); + public Task LongToNullableLong_Success() => + AssertConverterSuccess(new LongToNullableLongTypeConverter(), LongValue, (long?)LongValue); - /// - /// Verifies LongToNullableLongTypeConverter fails when given a wrong type. - /// + /// Verifies LongToNullableLongTypeConverter fails when given a wrong type. /// A task representing the asynchronous test operation. [Test] - public async Task LongToNullableLong_Failure_WrongType() => - await AssertConverterFailure(new LongToNullableLongTypeConverter(), WrongTypeInput); + public Task LongToNullableLong_Failure_WrongType() => + AssertConverterFailure(new LongToNullableLongTypeConverter(), WrongTypeInput); - /// - /// Verifies LongToNullableLongTypeConverter fails when given null. - /// + /// Verifies LongToNullableLongTypeConverter fails when given null. /// A task representing the asynchronous test operation. [Test] - public async Task LongToNullableLong_Failure_Null() => - await AssertConverterFailure(new LongToNullableLongTypeConverter(), null); + public Task LongToNullableLong_Failure_Null() => + AssertConverterFailure(new LongToNullableLongTypeConverter(), null); - /// - /// Verifies ShortToNullableShortTypeConverter converts a short to nullable short. - /// + /// Verifies ShortToNullableShortTypeConverter converts a short to nullable short. /// A task representing the asynchronous test operation. [Test] - public async Task ShortToNullableShort_Success() => - await AssertConverterSuccess(new ShortToNullableShortTypeConverter(), (short)ShortValue, (short?)ShortValue); + public Task ShortToNullableShort_Success() => + AssertConverterSuccess(new ShortToNullableShortTypeConverter(), ShortValue, (short?)ShortValue); - /// - /// Verifies ShortToNullableShortTypeConverter fails when given a wrong type. - /// + /// Verifies ShortToNullableShortTypeConverter fails when given a wrong type. /// A task representing the asynchronous test operation. [Test] - public async Task ShortToNullableShort_Failure_WrongType() => - await AssertConverterFailure(new ShortToNullableShortTypeConverter(), WrongTypeInput); + public Task ShortToNullableShort_Failure_WrongType() => + AssertConverterFailure(new ShortToNullableShortTypeConverter(), WrongTypeInput); - /// - /// Verifies ShortToNullableShortTypeConverter fails when given null. - /// + /// Verifies ShortToNullableShortTypeConverter fails when given null. /// A task representing the asynchronous test operation. [Test] - public async Task ShortToNullableShort_Failure_Null() => - await AssertConverterFailure(new ShortToNullableShortTypeConverter(), null); + public Task ShortToNullableShort_Failure_Null() => + AssertConverterFailure(new ShortToNullableShortTypeConverter(), null); - /// - /// Verifies SingleToNullableSingleTypeConverter converts a float to nullable float. - /// + /// Verifies SingleToNullableSingleTypeConverter converts a float to nullable float. /// A task representing the asynchronous test operation. [Test] - public async Task SingleToNullableSingle_Success() => - await AssertConverterSuccess(new SingleToNullableSingleTypeConverter(), SingleValue, (float?)SingleValue); + public Task SingleToNullableSingle_Success() => + AssertConverterSuccess(new SingleToNullableSingleTypeConverter(), SingleValue, (float?)SingleValue); - /// - /// Verifies SingleToNullableSingleTypeConverter fails when given a wrong type. - /// + /// Verifies SingleToNullableSingleTypeConverter fails when given a wrong type. /// A task representing the asynchronous test operation. [Test] - public async Task SingleToNullableSingle_Failure_WrongType() => - await AssertConverterFailure(new SingleToNullableSingleTypeConverter(), WrongTypeInput); + public Task SingleToNullableSingle_Failure_WrongType() => + AssertConverterFailure(new SingleToNullableSingleTypeConverter(), WrongTypeInput); - /// - /// Verifies SingleToNullableSingleTypeConverter fails when given null. - /// + /// Verifies SingleToNullableSingleTypeConverter fails when given null. /// A task representing the asynchronous test operation. [Test] - public async Task SingleToNullableSingle_Failure_Null() => - await AssertConverterFailure(new SingleToNullableSingleTypeConverter(), null); + public Task SingleToNullableSingle_Failure_Null() => + AssertConverterFailure(new SingleToNullableSingleTypeConverter(), null); - /// - /// Verifies DecimalToNullableDecimalTypeConverter converts a decimal to nullable decimal. - /// + /// Verifies DecimalToNullableDecimalTypeConverter converts a decimal to nullable decimal. /// A task representing the asynchronous test operation. [Test] - public async Task DecimalToNullableDecimal_Success() => - await AssertConverterSuccess(new DecimalToNullableDecimalTypeConverter(), DecimalValue, (decimal?)DecimalValue); + public Task DecimalToNullableDecimal_Success() => + AssertConverterSuccess(new DecimalToNullableDecimalTypeConverter(), DecimalValue, (decimal?)DecimalValue); - /// - /// Verifies DecimalToNullableDecimalTypeConverter fails when given a wrong type. - /// + /// Verifies DecimalToNullableDecimalTypeConverter fails when given a wrong type. /// A task representing the asynchronous test operation. [Test] - public async Task DecimalToNullableDecimal_Failure_WrongType() => - await AssertConverterFailure(new DecimalToNullableDecimalTypeConverter(), WrongTypeInput); + public Task DecimalToNullableDecimal_Failure_WrongType() => + AssertConverterFailure(new DecimalToNullableDecimalTypeConverter(), WrongTypeInput); - /// - /// Verifies DecimalToNullableDecimalTypeConverter fails when given null. - /// + /// Verifies DecimalToNullableDecimalTypeConverter fails when given null. /// A task representing the asynchronous test operation. [Test] - public async Task DecimalToNullableDecimal_Failure_Null() => - await AssertConverterFailure(new DecimalToNullableDecimalTypeConverter(), null); + public Task DecimalToNullableDecimal_Failure_Null() => + AssertConverterFailure(new DecimalToNullableDecimalTypeConverter(), null); // =================================================================== // Nullable-to-Value converters // =================================================================== - - /// - /// Verifies NullableDoubleToDoubleTypeConverter converts a double value successfully. - /// + /// Verifies NullableDoubleToDoubleTypeConverter converts a double value successfully. /// A task representing the asynchronous test operation. [Test] - public async Task NullableDoubleToDouble_Success() => - await AssertConverterSuccess(new NullableDoubleToDoubleTypeConverter(), DoubleValue, DoubleValue); + public Task NullableDoubleToDouble_Success() => + AssertConverterSuccess(new NullableDoubleToDoubleTypeConverter(), DoubleValue, DoubleValue); - /// - /// Verifies NullableDoubleToDoubleTypeConverter fails when given a wrong type. - /// + /// Verifies NullableDoubleToDoubleTypeConverter fails when given a wrong type. /// A task representing the asynchronous test operation. [Test] - public async Task NullableDoubleToDouble_Failure_WrongType() => - await AssertConverterFailure(new NullableDoubleToDoubleTypeConverter(), WrongTypeInput); + public Task NullableDoubleToDouble_Failure_WrongType() => + AssertConverterFailure(new NullableDoubleToDoubleTypeConverter(), WrongTypeInput); - /// - /// Verifies NullableDoubleToDoubleTypeConverter fails when given null. - /// + /// Verifies NullableDoubleToDoubleTypeConverter fails when given null. /// A task representing the asynchronous test operation. [Test] - public async Task NullableDoubleToDouble_Failure_Null() => - await AssertConverterFailure(new NullableDoubleToDoubleTypeConverter(), null); + public Task NullableDoubleToDouble_Failure_Null() => + AssertConverterFailure(new NullableDoubleToDoubleTypeConverter(), null); - /// - /// Verifies NullableIntegerToIntegerTypeConverter converts an int value successfully. - /// + /// Verifies NullableIntegerToIntegerTypeConverter converts an int value successfully. /// A task representing the asynchronous test operation. [Test] - public async Task NullableIntegerToInteger_Success() => - await AssertConverterSuccess(new NullableIntegerToIntegerTypeConverter(), SmallIntValue, SmallIntValue); + public Task NullableIntegerToInteger_Success() => + AssertConverterSuccess(new NullableIntegerToIntegerTypeConverter(), SmallIntValue, SmallIntValue); - /// - /// Verifies NullableIntegerToIntegerTypeConverter fails when given a wrong type. - /// + /// Verifies NullableIntegerToIntegerTypeConverter fails when given a wrong type. /// A task representing the asynchronous test operation. [Test] - public async Task NullableIntegerToInteger_Failure_WrongType() => - await AssertConverterFailure(new NullableIntegerToIntegerTypeConverter(), WrongTypeInput); + public Task NullableIntegerToInteger_Failure_WrongType() => + AssertConverterFailure(new NullableIntegerToIntegerTypeConverter(), WrongTypeInput); - /// - /// Verifies NullableIntegerToIntegerTypeConverter fails when given null. - /// + /// Verifies NullableIntegerToIntegerTypeConverter fails when given null. /// A task representing the asynchronous test operation. [Test] - public async Task NullableIntegerToInteger_Failure_Null() => - await AssertConverterFailure(new NullableIntegerToIntegerTypeConverter(), null); + public Task NullableIntegerToInteger_Failure_Null() => + AssertConverterFailure(new NullableIntegerToIntegerTypeConverter(), null); - /// - /// Verifies NullableByteToByteTypeConverter converts a byte value successfully. - /// + /// Verifies NullableByteToByteTypeConverter converts a byte value successfully. /// A task representing the asynchronous test operation. [Test] - public async Task NullableByteToByte_Success() => - await AssertConverterSuccess(new NullableByteToByteTypeConverter(), (byte)SmallByteValue, (byte)SmallByteValue); + public Task NullableByteToByte_Success() => + AssertConverterSuccess(new NullableByteToByteTypeConverter(), SmallByteValue, SmallByteValue); - /// - /// Verifies NullableByteToByteTypeConverter fails when given a wrong type. - /// + /// Verifies NullableByteToByteTypeConverter fails when given a wrong type. /// A task representing the asynchronous test operation. [Test] - public async Task NullableByteToByte_Failure_WrongType() => - await AssertConverterFailure(new NullableByteToByteTypeConverter(), WrongTypeInput); + public Task NullableByteToByte_Failure_WrongType() => + AssertConverterFailure(new NullableByteToByteTypeConverter(), WrongTypeInput); - /// - /// Verifies NullableByteToByteTypeConverter fails when given null. - /// + /// Verifies NullableByteToByteTypeConverter fails when given null. /// A task representing the asynchronous test operation. [Test] - public async Task NullableByteToByte_Failure_Null() => - await AssertConverterFailure(new NullableByteToByteTypeConverter(), null); + public Task NullableByteToByte_Failure_Null() => + AssertConverterFailure(new NullableByteToByteTypeConverter(), null); - /// - /// Verifies NullableLongToLongTypeConverter converts a long value successfully. - /// + /// Verifies NullableLongToLongTypeConverter converts a long value successfully. /// A task representing the asynchronous test operation. [Test] - public async Task NullableLongToLong_Success() => - await AssertConverterSuccess(new NullableLongToLongTypeConverter(), LongValue, LongValue); + public Task NullableLongToLong_Success() => + AssertConverterSuccess(new NullableLongToLongTypeConverter(), LongValue, LongValue); - /// - /// Verifies NullableLongToLongTypeConverter fails when given a wrong type. - /// + /// Verifies NullableLongToLongTypeConverter fails when given a wrong type. /// A task representing the asynchronous test operation. [Test] - public async Task NullableLongToLong_Failure_WrongType() => - await AssertConverterFailure(new NullableLongToLongTypeConverter(), WrongTypeInput); + public Task NullableLongToLong_Failure_WrongType() => + AssertConverterFailure(new NullableLongToLongTypeConverter(), WrongTypeInput); - /// - /// Verifies NullableLongToLongTypeConverter fails when given null. - /// + /// Verifies NullableLongToLongTypeConverter fails when given null. /// A task representing the asynchronous test operation. [Test] - public async Task NullableLongToLong_Failure_Null() => - await AssertConverterFailure(new NullableLongToLongTypeConverter(), null); + public Task NullableLongToLong_Failure_Null() => + AssertConverterFailure(new NullableLongToLongTypeConverter(), null); - /// - /// Verifies NullableShortToShortTypeConverter converts a short value successfully. - /// + /// Verifies NullableShortToShortTypeConverter converts a short value successfully. /// A task representing the asynchronous test operation. [Test] - public async Task NullableShortToShort_Success() => - await AssertConverterSuccess(new NullableShortToShortTypeConverter(), (short)ShortValue, (short)ShortValue); + public Task NullableShortToShort_Success() => + AssertConverterSuccess(new NullableShortToShortTypeConverter(), ShortValue, ShortValue); - /// - /// Verifies NullableShortToShortTypeConverter fails when given a wrong type. - /// + /// Verifies NullableShortToShortTypeConverter fails when given a wrong type. /// A task representing the asynchronous test operation. [Test] - public async Task NullableShortToShort_Failure_WrongType() => - await AssertConverterFailure(new NullableShortToShortTypeConverter(), WrongTypeInput); + public Task NullableShortToShort_Failure_WrongType() => + AssertConverterFailure(new NullableShortToShortTypeConverter(), WrongTypeInput); - /// - /// Verifies NullableShortToShortTypeConverter fails when given null. - /// + /// Verifies NullableShortToShortTypeConverter fails when given null. /// A task representing the asynchronous test operation. [Test] - public async Task NullableShortToShort_Failure_Null() => - await AssertConverterFailure(new NullableShortToShortTypeConverter(), null); + public Task NullableShortToShort_Failure_Null() => + AssertConverterFailure(new NullableShortToShortTypeConverter(), null); - /// - /// Verifies NullableSingleToSingleTypeConverter converts a float value successfully. - /// + /// Verifies NullableSingleToSingleTypeConverter converts a float value successfully. /// A task representing the asynchronous test operation. [Test] - public async Task NullableSingleToSingle_Success() => - await AssertConverterSuccess(new NullableSingleToSingleTypeConverter(), SingleValue, SingleValue); + public Task NullableSingleToSingle_Success() => + AssertConverterSuccess(new NullableSingleToSingleTypeConverter(), SingleValue, SingleValue); - /// - /// Verifies NullableSingleToSingleTypeConverter fails when given a wrong type. - /// + /// Verifies NullableSingleToSingleTypeConverter fails when given a wrong type. /// A task representing the asynchronous test operation. [Test] - public async Task NullableSingleToSingle_Failure_WrongType() => - await AssertConverterFailure(new NullableSingleToSingleTypeConverter(), WrongTypeInput); + public Task NullableSingleToSingle_Failure_WrongType() => + AssertConverterFailure(new NullableSingleToSingleTypeConverter(), WrongTypeInput); - /// - /// Verifies NullableSingleToSingleTypeConverter fails when given null. - /// + /// Verifies NullableSingleToSingleTypeConverter fails when given null. /// A task representing the asynchronous test operation. [Test] - public async Task NullableSingleToSingle_Failure_Null() => - await AssertConverterFailure(new NullableSingleToSingleTypeConverter(), null); + public Task NullableSingleToSingle_Failure_Null() => + AssertConverterFailure(new NullableSingleToSingleTypeConverter(), null); - /// - /// Verifies NullableDecimalToDecimalTypeConverter converts a decimal value successfully. - /// + /// Verifies NullableDecimalToDecimalTypeConverter converts a decimal value successfully. /// A task representing the asynchronous test operation. [Test] - public async Task NullableDecimalToDecimal_Success() => - await AssertConverterSuccess(new NullableDecimalToDecimalTypeConverter(), DecimalValue, DecimalValue); + public Task NullableDecimalToDecimal_Success() => + AssertConverterSuccess(new NullableDecimalToDecimalTypeConverter(), DecimalValue, DecimalValue); - /// - /// Verifies NullableDecimalToDecimalTypeConverter fails when given a wrong type. - /// + /// Verifies NullableDecimalToDecimalTypeConverter fails when given a wrong type. /// A task representing the asynchronous test operation. [Test] - public async Task NullableDecimalToDecimal_Failure_WrongType() => - await AssertConverterFailure(new NullableDecimalToDecimalTypeConverter(), WrongTypeInput); + public Task NullableDecimalToDecimal_Failure_WrongType() => + AssertConverterFailure(new NullableDecimalToDecimalTypeConverter(), WrongTypeInput); - /// - /// Verifies NullableDecimalToDecimalTypeConverter fails when given null. - /// + /// Verifies NullableDecimalToDecimalTypeConverter fails when given null. /// A task representing the asynchronous test operation. [Test] - public async Task NullableDecimalToDecimal_Failure_Null() => - await AssertConverterFailure(new NullableDecimalToDecimalTypeConverter(), null); + public Task NullableDecimalToDecimal_Failure_Null() => + AssertConverterFailure(new NullableDecimalToDecimalTypeConverter(), null); - /// - /// Asserts that the converter successfully converts the input to the expected output. - /// + /// Asserts that the converter successfully converts the input to the expected output. /// The converter to test. /// The input value to convert. /// The expected conversion result. @@ -767,9 +568,7 @@ private static async Task AssertConverterSuccess( await Assert.That(result).IsEqualTo(expectedOutput); } - /// - /// Asserts that the converter fails to convert the given input. - /// + /// Asserts that the converter fails to convert the given input. /// The converter to test. /// The input value that should fail conversion. /// A task representing the asynchronous test operation. diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/BindingTypeConvertersUnitTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/BindingTypeConvertersUnitTests.cs index b978d33..ef14764 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/BindingTypeConvertersUnitTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/BindingTypeConvertersUnitTests.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding.Tests.Bindings; -/// -/// Unit tests for standard binding type converters verifying basic conversion correctness. -/// +/// Unit tests for standard binding type converters verifying basic conversion correctness. public class BindingTypeConvertersUnitTests { - /// - /// Verifies that ByteToStringTypeConverter converts correctly. - /// + /// Verifies that ByteToStringTypeConverter converts correctly. /// A task representing the asynchronous operation. [Test] public async Task ByteToStringTypeConverter_Converts_Correctly() @@ -25,24 +21,20 @@ public async Task ByteToStringTypeConverter_Converts_Correctly() await Assert.That(output).IsEqualTo("123"); } - /// - /// Verifies that DecimalToStringTypeConverter converts correctly. - /// + /// Verifies that DecimalToStringTypeConverter converts correctly. /// A task representing the asynchronous operation. [Test] public async Task DecimalToStringTypeConverter_Converts_Correctly() { var converter = new DecimalToStringTypeConverter(); - const decimal val = 123.456m; + const decimal val = 123.456M; var result = converter.TryConvert(val, null, out var output); await Assert.That(result).IsTrue(); await Assert.That(output).IsEqualTo(val.ToString(System.Globalization.CultureInfo.CurrentCulture)); } - /// - /// Verifies that DoubleToStringTypeConverter converts correctly. - /// + /// Verifies that DoubleToStringTypeConverter converts correctly. /// A task representing the asynchronous operation. [Test] public async Task DoubleToStringTypeConverter_Converts_Correctly() @@ -55,9 +47,7 @@ public async Task DoubleToStringTypeConverter_Converts_Correctly() await Assert.That(output).IsEqualTo(val.ToString(System.Globalization.CultureInfo.CurrentCulture)); } - /// - /// Verifies that IntegerToStringTypeConverter converts correctly. - /// + /// Verifies that IntegerToStringTypeConverter converts correctly. /// A task representing the asynchronous operation. [Test] public async Task IntegerToStringTypeConverter_Converts_Correctly() @@ -70,9 +60,7 @@ public async Task IntegerToStringTypeConverter_Converts_Correctly() await Assert.That(output).IsEqualTo("123456789"); } - /// - /// Verifies that LongToStringTypeConverter converts correctly. - /// + /// Verifies that LongToStringTypeConverter converts correctly. /// A task representing the asynchronous operation. [Test] public async Task LongToStringTypeConverter_Converts_Correctly() @@ -85,9 +73,7 @@ public async Task LongToStringTypeConverter_Converts_Correctly() await Assert.That(output).IsEqualTo("1234567890123456789"); } - /// - /// Verifies that NullableByteToStringTypeConverter converts correctly. - /// + /// Verifies that NullableByteToStringTypeConverter converts correctly. /// A task representing the asynchronous operation. [Test] public async Task NullableByteToStringTypeConverter_Converts_Correctly() @@ -101,24 +87,20 @@ public async Task NullableByteToStringTypeConverter_Converts_Correctly() await Assert.That(output).IsEqualTo("123"); } - /// - /// Verifies that NullableDecimalToStringTypeConverter converts correctly. - /// + /// Verifies that NullableDecimalToStringTypeConverter converts correctly. /// A task representing the asynchronous operation. [Test] public async Task NullableDecimalToStringTypeConverter_Converts_Correctly() { var converter = new NullableDecimalToStringTypeConverter(); - decimal? val = 123.456m; + decimal? val = 123.456M; var result = converter.TryConvert(val, null, out var output); await Assert.That(result).IsTrue(); await Assert.That(output).IsEqualTo(val.ToString()); } - /// - /// Verifies that NullableDoubleToStringTypeConverter converts correctly. - /// + /// Verifies that NullableDoubleToStringTypeConverter converts correctly. /// A task representing the asynchronous operation. [Test] public async Task NullableDoubleToStringTypeConverter_Converts_Correctly() @@ -131,9 +113,7 @@ public async Task NullableDoubleToStringTypeConverter_Converts_Correctly() await Assert.That(output).IsEqualTo(val.ToString()); } - /// - /// Verifies that NullableIntegerToStringTypeConverter converts correctly. - /// + /// Verifies that NullableIntegerToStringTypeConverter converts correctly. /// A task representing the asynchronous operation. [Test] public async Task NullableIntegerToStringTypeConverter_Converts_Correctly() @@ -146,9 +126,7 @@ public async Task NullableIntegerToStringTypeConverter_Converts_Correctly() await Assert.That(output).IsEqualTo("123456789"); } - /// - /// Verifies that NullableLongToStringTypeConverter converts correctly. - /// + /// Verifies that NullableLongToStringTypeConverter converts correctly. /// A task representing the asynchronous operation. [Test] public async Task NullableLongToStringTypeConverter_Converts_Correctly() @@ -161,9 +139,7 @@ public async Task NullableLongToStringTypeConverter_Converts_Correctly() await Assert.That(output).IsEqualTo("1234567890123456789"); } - /// - /// Verifies that NullableShortToStringTypeConverter converts correctly. - /// + /// Verifies that NullableShortToStringTypeConverter converts correctly. /// A task representing the asynchronous operation. [Test] public async Task NullableShortToStringTypeConverter_Converts_Correctly() @@ -176,24 +152,20 @@ public async Task NullableShortToStringTypeConverter_Converts_Correctly() await Assert.That(output).IsEqualTo("12345"); } - /// - /// Verifies that NullableSingleToStringTypeConverter converts correctly. - /// + /// Verifies that NullableSingleToStringTypeConverter converts correctly. /// A task representing the asynchronous operation. [Test] public async Task NullableSingleToStringTypeConverter_Converts_Correctly() { var converter = new NullableSingleToStringTypeConverter(); - float? val = 123.45f; + float? val = 123.45F; var result = converter.TryConvert(val, null, out var output); await Assert.That(result).IsTrue(); await Assert.That(output).IsEqualTo(val.ToString()); } - /// - /// Verifies that ShortToStringTypeConverter converts correctly. - /// + /// Verifies that ShortToStringTypeConverter converts correctly. /// A task representing the asynchronous operation. [Test] public async Task ShortToStringTypeConverter_Converts_Correctly() @@ -206,15 +178,13 @@ public async Task ShortToStringTypeConverter_Converts_Correctly() await Assert.That(output).IsEqualTo("12345"); } - /// - /// Verifies that SingleToStringTypeConverter converts correctly. - /// + /// Verifies that SingleToStringTypeConverter converts correctly. /// A task representing the asynchronous operation. [Test] public async Task SingleToStringTypeConverter_Converts_Correctly() { var converter = new SingleToStringTypeConverter(); - const float val = 123.45f; + const float val = 123.45F; var result = converter.TryConvert(val, null, out var output); await Assert.That(result).IsTrue(); diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/Converters/BindingTypeConverterRegistryTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/Converters/BindingTypeConverterRegistryTests.cs index 5f87faa..3ba80c2 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/Converters/BindingTypeConverterRegistryTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/Converters/BindingTypeConverterRegistryTests.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding.Tests.Bindings.Converters; -/// -/// Tests for the internal method. -/// +/// Tests for the internal method. public class BindingTypeConverterRegistryTests { - /// - /// Verifies that CloneRegistryShallow returns an empty dictionary for empty input. - /// + /// Verifies that CloneRegistryShallow returns an empty dictionary for empty input. /// A task representing the asynchronous test operation. [Test] public async Task CloneRegistryShallow_EmptyDictionary_ReturnsEmpty() @@ -23,19 +19,14 @@ public async Task CloneRegistryShallow_EmptyDictionary_ReturnsEmpty() await Assert.That(clone.Count).IsEqualTo(0); } - /// - /// Verifies that CloneRegistryShallow returns a shallow copy with the same entries. - /// + /// Verifies that CloneRegistryShallow returns a shallow copy with the same entries. /// A task representing the asynchronous test operation. [Test] public async Task CloneRegistryShallow_WithEntries_ReturnsShallowCopy() { var converter = new TestConverter(typeof(string), typeof(int)); var list = new List { converter }; - var source = new Dictionary<(Type fromType, Type toType), List> - { - [(typeof(string), typeof(int))] = list - }; + var source = new Dictionary<(Type fromType, Type toType), List> { [(typeof(string), typeof(int))] = list }; var clone = BindingTypeConverterRegistry.CloneRegistryShallow(source); @@ -47,47 +38,38 @@ public async Task CloneRegistryShallow_WithEntries_ReturnsShallowCopy() await Assert.That(ReferenceEquals(clonedList, list)).IsTrue(); } - /// - /// Verifies that modifying the clone does not affect the original dictionary. - /// + /// Verifies that modifying the clone does not affect the original dictionary. /// A task representing the asynchronous test operation. [Test] public async Task CloneRegistryShallow_ModifyingClone_DoesNotAffectOriginal() { var converter = new TestConverter(typeof(string), typeof(int)); var list = new List { converter }; - var source = new Dictionary<(Type fromType, Type toType), List> - { - [(typeof(string), typeof(int))] = list - }; + var source = new Dictionary<(Type fromType, Type toType), List> { [(typeof(string), typeof(int))] = list }; var clone = BindingTypeConverterRegistry.CloneRegistryShallow(source); // Remove entry from clone - clone.Remove((typeof(string), typeof(int))); + _ = clone.Remove((typeof(string), typeof(int))); // Original should still have the entry await Assert.That(source.Count).IsEqualTo(1); await Assert.That(clone.Count).IsEqualTo(0); } - /// - /// Verifies that CloneRegistryShallow throws ArgumentNullException for null input. - /// + /// Verifies that CloneRegistryShallow throws ArgumentNullException for null input. /// A task representing the asynchronous test operation. [Test] public async Task CloneRegistryShallow_NullInput_ThrowsArgumentNullException() => - await Assert.That(() => BindingTypeConverterRegistry.CloneRegistryShallow(null!)) + await Assert.That(static () => BindingTypeConverterRegistry.CloneRegistryShallow(null!)) .ThrowsExactly(); - /// - /// Minimal test implementation of . - /// + /// Minimal test implementation of . + /// The source type this converter claims to handle. + /// The target type this converter claims to handle. private sealed class TestConverter(Type fromType, Type toType) : IBindingTypeConverter { - /// - /// Affinity returned by this stub converter indicating a strong match. - /// + /// Affinity returned by this stub converter indicating a strong match. private const int StubAffinity = 2; /// diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/Converters/ConverterAffinityTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/Converters/ConverterAffinityTests.cs index 394a2ac..0b1d9bf 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/Converters/ConverterAffinityTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/Converters/ConverterAffinityTests.cs @@ -4,548 +4,409 @@ namespace ReactiveUI.Binding.Tests.Bindings.Converters; -/// -/// Tests for verifying converter affinity values are correctly set. -/// +/// Tests for verifying converter affinity values are correctly set. public class ConverterAffinityTests { - /// - /// The last-resort affinity reported by the equality converter. - /// + /// The last-resort affinity reported by the equality converter. private const int LastResortAffinity = 1; - /// - /// The standard affinity reported by string-based type converters. - /// + /// The standard affinity reported by string-based type converters. private const int StringConverterAffinity = 2; - /// - /// Verifies that the EqualityTypeConverter has affinity 1 (last resort). - /// + /// Verifies that the EqualityTypeConverter has affinity 1 (last resort). /// A task representing the asynchronous test operation. [Test] - public async Task EqualityConverter_ShouldHaveAffinity1() => - await AssertAffinity(new EqualityTypeConverter(), LastResortAffinity); + public Task EqualityConverter_ShouldHaveAffinity1() => + AssertAffinity(new EqualityTypeConverter(), LastResortAffinity); // =================================================================== // String identity converter // =================================================================== - - /// - /// Verifies that StringConverter has affinity 2. - /// + /// Verifies that StringConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringConverter(), StringConverterAffinity); + public Task StringConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringConverter(), StringConverterAffinity); // =================================================================== // Numeric → String converters // =================================================================== - - /// - /// Verifies that ByteToStringTypeConverter has affinity 2. - /// + /// Verifies that ByteToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task ByteToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new ByteToStringTypeConverter(), StringConverterAffinity); + public Task ByteToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new ByteToStringTypeConverter(), StringConverterAffinity); - /// - /// Verifies that NullableByteToStringTypeConverter has affinity 2. - /// + /// Verifies that NullableByteToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task NullableByteToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new NullableByteToStringTypeConverter(), StringConverterAffinity); + public Task NullableByteToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new NullableByteToStringTypeConverter(), StringConverterAffinity); - /// - /// Verifies that ShortToStringTypeConverter has affinity 2. - /// + /// Verifies that ShortToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task ShortToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new ShortToStringTypeConverter(), StringConverterAffinity); + public Task ShortToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new ShortToStringTypeConverter(), StringConverterAffinity); - /// - /// Verifies that NullableShortToStringTypeConverter has affinity 2. - /// + /// Verifies that NullableShortToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task NullableShortToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new NullableShortToStringTypeConverter(), StringConverterAffinity); + public Task NullableShortToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new NullableShortToStringTypeConverter(), StringConverterAffinity); - /// - /// Verifies that IntegerToStringTypeConverter has affinity 2. - /// + /// Verifies that IntegerToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task IntegerToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new IntegerToStringTypeConverter(), StringConverterAffinity); + public Task IntegerToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new IntegerToStringTypeConverter(), StringConverterAffinity); - /// - /// Verifies that NullableIntegerToStringTypeConverter has affinity 2. - /// + /// Verifies that NullableIntegerToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task NullableIntegerToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new NullableIntegerToStringTypeConverter(), StringConverterAffinity); + public Task NullableIntegerToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new NullableIntegerToStringTypeConverter(), StringConverterAffinity); - /// - /// Verifies that LongToStringTypeConverter has affinity 2. - /// + /// Verifies that LongToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task LongToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new LongToStringTypeConverter(), StringConverterAffinity); + public Task LongToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new LongToStringTypeConverter(), StringConverterAffinity); - /// - /// Verifies that NullableLongToStringTypeConverter has affinity 2. - /// + /// Verifies that NullableLongToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task NullableLongToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new NullableLongToStringTypeConverter(), StringConverterAffinity); + public Task NullableLongToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new NullableLongToStringTypeConverter(), StringConverterAffinity); - /// - /// Verifies that SingleToStringTypeConverter has affinity 2. - /// + /// Verifies that SingleToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task SingleToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new SingleToStringTypeConverter(), StringConverterAffinity); + public Task SingleToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new SingleToStringTypeConverter(), StringConverterAffinity); - /// - /// Verifies that NullableSingleToStringTypeConverter has affinity 2. - /// + /// Verifies that NullableSingleToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task NullableSingleToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new NullableSingleToStringTypeConverter(), StringConverterAffinity); + public Task NullableSingleToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new NullableSingleToStringTypeConverter(), StringConverterAffinity); - /// - /// Verifies that DoubleToStringTypeConverter has affinity 2. - /// + /// Verifies that DoubleToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task DoubleToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new DoubleToStringTypeConverter(), StringConverterAffinity); + public Task DoubleToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new DoubleToStringTypeConverter(), StringConverterAffinity); - /// - /// Verifies that NullableDoubleToStringTypeConverter has affinity 2. - /// + /// Verifies that NullableDoubleToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task NullableDoubleToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new NullableDoubleToStringTypeConverter(), StringConverterAffinity); + public Task NullableDoubleToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new NullableDoubleToStringTypeConverter(), StringConverterAffinity); - /// - /// Verifies that DecimalToStringTypeConverter has affinity 2. - /// + /// Verifies that DecimalToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task DecimalToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new DecimalToStringTypeConverter(), StringConverterAffinity); + public Task DecimalToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new DecimalToStringTypeConverter(), StringConverterAffinity); - /// - /// Verifies that NullableDecimalToStringTypeConverter has affinity 2. - /// + /// Verifies that NullableDecimalToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task NullableDecimalToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new NullableDecimalToStringTypeConverter(), StringConverterAffinity); + public Task NullableDecimalToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new NullableDecimalToStringTypeConverter(), StringConverterAffinity); // =================================================================== // String → Numeric converters // =================================================================== - - /// - /// Verifies that StringToByteTypeConverter has affinity 2. - /// + /// Verifies that StringToByteTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToByteTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToByteTypeConverter(), StringConverterAffinity); + public Task StringToByteTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToByteTypeConverter(), StringConverterAffinity); - /// - /// Verifies that StringToNullableByteTypeConverter has affinity 2. - /// + /// Verifies that StringToNullableByteTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToNullableByteTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToNullableByteTypeConverter(), StringConverterAffinity); + public Task StringToNullableByteTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToNullableByteTypeConverter(), StringConverterAffinity); - /// - /// Verifies that StringToShortTypeConverter has affinity 2. - /// + /// Verifies that StringToShortTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToShortTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToShortTypeConverter(), StringConverterAffinity); + public Task StringToShortTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToShortTypeConverter(), StringConverterAffinity); - /// - /// Verifies that StringToNullableShortTypeConverter has affinity 2. - /// + /// Verifies that StringToNullableShortTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToNullableShortTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToNullableShortTypeConverter(), StringConverterAffinity); + public Task StringToNullableShortTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToNullableShortTypeConverter(), StringConverterAffinity); - /// - /// Verifies that StringToIntegerTypeConverter has affinity 2. - /// + /// Verifies that StringToIntegerTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToIntegerTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToIntegerTypeConverter(), StringConverterAffinity); + public Task StringToIntegerTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToIntegerTypeConverter(), StringConverterAffinity); - /// - /// Verifies that StringToNullableIntegerTypeConverter has affinity 2. - /// + /// Verifies that StringToNullableIntegerTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToNullableIntegerTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToNullableIntegerTypeConverter(), StringConverterAffinity); + public Task StringToNullableIntegerTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToNullableIntegerTypeConverter(), StringConverterAffinity); - /// - /// Verifies that StringToLongTypeConverter has affinity 2. - /// + /// Verifies that StringToLongTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToLongTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToLongTypeConverter(), StringConverterAffinity); + public Task StringToLongTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToLongTypeConverter(), StringConverterAffinity); - /// - /// Verifies that StringToNullableLongTypeConverter has affinity 2. - /// + /// Verifies that StringToNullableLongTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToNullableLongTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToNullableLongTypeConverter(), StringConverterAffinity); + public Task StringToNullableLongTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToNullableLongTypeConverter(), StringConverterAffinity); - /// - /// Verifies that StringToSingleTypeConverter has affinity 2. - /// + /// Verifies that StringToSingleTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToSingleTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToSingleTypeConverter(), StringConverterAffinity); + public Task StringToSingleTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToSingleTypeConverter(), StringConverterAffinity); - /// - /// Verifies that StringToNullableSingleTypeConverter has affinity 2. - /// + /// Verifies that StringToNullableSingleTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToNullableSingleTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToNullableSingleTypeConverter(), StringConverterAffinity); + public Task StringToNullableSingleTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToNullableSingleTypeConverter(), StringConverterAffinity); - /// - /// Verifies that StringToDoubleTypeConverter has affinity 2. - /// + /// Verifies that StringToDoubleTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToDoubleTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToDoubleTypeConverter(), StringConverterAffinity); + public Task StringToDoubleTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToDoubleTypeConverter(), StringConverterAffinity); - /// - /// Verifies that StringToNullableDoubleTypeConverter has affinity 2. - /// + /// Verifies that StringToNullableDoubleTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToNullableDoubleTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToNullableDoubleTypeConverter(), StringConverterAffinity); + public Task StringToNullableDoubleTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToNullableDoubleTypeConverter(), StringConverterAffinity); - /// - /// Verifies that StringToDecimalTypeConverter has affinity 2. - /// + /// Verifies that StringToDecimalTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToDecimalTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToDecimalTypeConverter(), StringConverterAffinity); + public Task StringToDecimalTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToDecimalTypeConverter(), StringConverterAffinity); - /// - /// Verifies that StringToNullableDecimalTypeConverter has affinity 2. - /// + /// Verifies that StringToNullableDecimalTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToNullableDecimalTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToNullableDecimalTypeConverter(), StringConverterAffinity); + public Task StringToNullableDecimalTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToNullableDecimalTypeConverter(), StringConverterAffinity); // =================================================================== // Boolean ↔ String converters // =================================================================== - - /// - /// Verifies that BooleanToStringTypeConverter has affinity 2. - /// + /// Verifies that BooleanToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task BooleanToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new BooleanToStringTypeConverter(), StringConverterAffinity); + public Task BooleanToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new BooleanToStringTypeConverter(), StringConverterAffinity); - /// - /// Verifies that NullableBooleanToStringTypeConverter has affinity 2. - /// + /// Verifies that NullableBooleanToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task NullableBooleanToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new NullableBooleanToStringTypeConverter(), StringConverterAffinity); + public Task NullableBooleanToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new NullableBooleanToStringTypeConverter(), StringConverterAffinity); - /// - /// Verifies that StringToBooleanTypeConverter has affinity 2. - /// + /// Verifies that StringToBooleanTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToBooleanTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToBooleanTypeConverter(), StringConverterAffinity); + public Task StringToBooleanTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToBooleanTypeConverter(), StringConverterAffinity); - /// - /// Verifies that StringToNullableBooleanTypeConverter has affinity 2. - /// + /// Verifies that StringToNullableBooleanTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToNullableBooleanTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToNullableBooleanTypeConverter(), StringConverterAffinity); + public Task StringToNullableBooleanTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToNullableBooleanTypeConverter(), StringConverterAffinity); // =================================================================== // Guid ↔ String converters // =================================================================== - - /// - /// Verifies that GuidToStringTypeConverter has affinity 2. - /// + /// Verifies that GuidToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task GuidToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new GuidToStringTypeConverter(), StringConverterAffinity); + public Task GuidToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new GuidToStringTypeConverter(), StringConverterAffinity); - /// - /// Verifies that NullableGuidToStringTypeConverter has affinity 2. - /// + /// Verifies that NullableGuidToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task NullableGuidToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new NullableGuidToStringTypeConverter(), StringConverterAffinity); + public Task NullableGuidToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new NullableGuidToStringTypeConverter(), StringConverterAffinity); - /// - /// Verifies that StringToGuidTypeConverter has affinity 2. - /// + /// Verifies that StringToGuidTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToGuidTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToGuidTypeConverter(), StringConverterAffinity); + public Task StringToGuidTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToGuidTypeConverter(), StringConverterAffinity); - /// - /// Verifies that StringToNullableGuidTypeConverter has affinity 2. - /// + /// Verifies that StringToNullableGuidTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToNullableGuidTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToNullableGuidTypeConverter(), StringConverterAffinity); + public Task StringToNullableGuidTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToNullableGuidTypeConverter(), StringConverterAffinity); // =================================================================== // DateTime ↔ String converters // =================================================================== - - /// - /// Verifies that DateTimeToStringTypeConverter has affinity 2. - /// + /// Verifies that DateTimeToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task DateTimeToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new DateTimeToStringTypeConverter(), StringConverterAffinity); + public Task DateTimeToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new DateTimeToStringTypeConverter(), StringConverterAffinity); - /// - /// Verifies that NullableDateTimeToStringTypeConverter has affinity 2. - /// + /// Verifies that NullableDateTimeToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task NullableDateTimeToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new NullableDateTimeToStringTypeConverter(), StringConverterAffinity); + public Task NullableDateTimeToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new NullableDateTimeToStringTypeConverter(), StringConverterAffinity); - /// - /// Verifies that StringToDateTimeTypeConverter has affinity 2. - /// + /// Verifies that StringToDateTimeTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToDateTimeTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToDateTimeTypeConverter(), StringConverterAffinity); + public Task StringToDateTimeTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToDateTimeTypeConverter(), StringConverterAffinity); - /// - /// Verifies that StringToNullableDateTimeTypeConverter has affinity 2. - /// + /// Verifies that StringToNullableDateTimeTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToNullableDateTimeTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToNullableDateTimeTypeConverter(), StringConverterAffinity); + public Task StringToNullableDateTimeTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToNullableDateTimeTypeConverter(), StringConverterAffinity); // =================================================================== // DateTimeOffset ↔ String converters // =================================================================== - - /// - /// Verifies that DateTimeOffsetToStringTypeConverter has affinity 2. - /// + /// Verifies that DateTimeOffsetToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task DateTimeOffsetToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new DateTimeOffsetToStringTypeConverter(), StringConverterAffinity); + public Task DateTimeOffsetToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new DateTimeOffsetToStringTypeConverter(), StringConverterAffinity); - /// - /// Verifies that NullableDateTimeOffsetToStringTypeConverter has affinity 2. - /// + /// Verifies that NullableDateTimeOffsetToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task NullableDateTimeOffsetToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new NullableDateTimeOffsetToStringTypeConverter(), StringConverterAffinity); + public Task NullableDateTimeOffsetToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new NullableDateTimeOffsetToStringTypeConverter(), StringConverterAffinity); - /// - /// Verifies that StringToDateTimeOffsetTypeConverter has affinity 2. - /// + /// Verifies that StringToDateTimeOffsetTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToDateTimeOffsetTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToDateTimeOffsetTypeConverter(), StringConverterAffinity); + public Task StringToDateTimeOffsetTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToDateTimeOffsetTypeConverter(), StringConverterAffinity); - /// - /// Verifies that StringToNullableDateTimeOffsetTypeConverter has affinity 2. - /// + /// Verifies that StringToNullableDateTimeOffsetTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToNullableDateTimeOffsetTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToNullableDateTimeOffsetTypeConverter(), StringConverterAffinity); + public Task StringToNullableDateTimeOffsetTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToNullableDateTimeOffsetTypeConverter(), StringConverterAffinity); // =================================================================== // TimeSpan ↔ String converters // =================================================================== - - /// - /// Verifies that TimeSpanToStringTypeConverter has affinity 2. - /// + /// Verifies that TimeSpanToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task TimeSpanToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new TimeSpanToStringTypeConverter(), StringConverterAffinity); + public Task TimeSpanToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new TimeSpanToStringTypeConverter(), StringConverterAffinity); - /// - /// Verifies that NullableTimeSpanToStringTypeConverter has affinity 2. - /// + /// Verifies that NullableTimeSpanToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task NullableTimeSpanToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new NullableTimeSpanToStringTypeConverter(), StringConverterAffinity); + public Task NullableTimeSpanToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new NullableTimeSpanToStringTypeConverter(), StringConverterAffinity); - /// - /// Verifies that StringToTimeSpanTypeConverter has affinity 2. - /// + /// Verifies that StringToTimeSpanTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToTimeSpanTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToTimeSpanTypeConverter(), StringConverterAffinity); + public Task StringToTimeSpanTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToTimeSpanTypeConverter(), StringConverterAffinity); - /// - /// Verifies that StringToNullableTimeSpanTypeConverter has affinity 2. - /// + /// Verifies that StringToNullableTimeSpanTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToNullableTimeSpanTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToNullableTimeSpanTypeConverter(), StringConverterAffinity); + public Task StringToNullableTimeSpanTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToNullableTimeSpanTypeConverter(), StringConverterAffinity); // =================================================================== // DateOnly ↔ String converters // =================================================================== - - /// - /// Verifies that DateOnlyToStringTypeConverter has affinity 2. - /// + /// Verifies that DateOnlyToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task DateOnlyToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new DateOnlyToStringTypeConverter(), StringConverterAffinity); + public Task DateOnlyToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new DateOnlyToStringTypeConverter(), StringConverterAffinity); - /// - /// Verifies that NullableDateOnlyToStringTypeConverter has affinity 2. - /// + /// Verifies that NullableDateOnlyToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task NullableDateOnlyToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new NullableDateOnlyToStringTypeConverter(), StringConverterAffinity); + public Task NullableDateOnlyToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new NullableDateOnlyToStringTypeConverter(), StringConverterAffinity); - /// - /// Verifies that StringToDateOnlyTypeConverter has affinity 2. - /// + /// Verifies that StringToDateOnlyTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToDateOnlyTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToDateOnlyTypeConverter(), StringConverterAffinity); + public Task StringToDateOnlyTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToDateOnlyTypeConverter(), StringConverterAffinity); - /// - /// Verifies that StringToNullableDateOnlyTypeConverter has affinity 2. - /// + /// Verifies that StringToNullableDateOnlyTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToNullableDateOnlyTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToNullableDateOnlyTypeConverter(), StringConverterAffinity); + public Task StringToNullableDateOnlyTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToNullableDateOnlyTypeConverter(), StringConverterAffinity); // =================================================================== // TimeOnly ↔ String converters // =================================================================== - - /// - /// Verifies that TimeOnlyToStringTypeConverter has affinity 2. - /// + /// Verifies that TimeOnlyToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task TimeOnlyToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new TimeOnlyToStringTypeConverter(), StringConverterAffinity); + public Task TimeOnlyToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new TimeOnlyToStringTypeConverter(), StringConverterAffinity); - /// - /// Verifies that NullableTimeOnlyToStringTypeConverter has affinity 2. - /// + /// Verifies that NullableTimeOnlyToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task NullableTimeOnlyToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new NullableTimeOnlyToStringTypeConverter(), StringConverterAffinity); + public Task NullableTimeOnlyToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new NullableTimeOnlyToStringTypeConverter(), StringConverterAffinity); - /// - /// Verifies that StringToTimeOnlyTypeConverter has affinity 2. - /// + /// Verifies that StringToTimeOnlyTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToTimeOnlyTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToTimeOnlyTypeConverter(), StringConverterAffinity); + public Task StringToTimeOnlyTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToTimeOnlyTypeConverter(), StringConverterAffinity); - /// - /// Verifies that StringToNullableTimeOnlyTypeConverter has affinity 2. - /// + /// Verifies that StringToNullableTimeOnlyTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToNullableTimeOnlyTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToNullableTimeOnlyTypeConverter(), StringConverterAffinity); + public Task StringToNullableTimeOnlyTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToNullableTimeOnlyTypeConverter(), StringConverterAffinity); // =================================================================== // Uri ↔ String converters // =================================================================== - - /// - /// Verifies that UriToStringTypeConverter has affinity 2. - /// + /// Verifies that UriToStringTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task UriToStringTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new UriToStringTypeConverter(), StringConverterAffinity); + public Task UriToStringTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new UriToStringTypeConverter(), StringConverterAffinity); - /// - /// Verifies that StringToUriTypeConverter has affinity 2. - /// + /// Verifies that StringToUriTypeConverter has affinity 2. /// A task representing the asynchronous test operation. [Test] - public async Task StringToUriTypeConverter_ShouldHaveAffinity2() => - await AssertAffinity(new StringToUriTypeConverter(), StringConverterAffinity); + public Task StringToUriTypeConverter_ShouldHaveAffinity2() => + AssertAffinity(new StringToUriTypeConverter(), StringConverterAffinity); - /// - /// Asserts that the specified converter reports the expected affinity value. - /// + /// Asserts that the specified converter reports the expected affinity value. /// The converter to test. /// The expected affinity value. /// A task representing the asynchronous test operation. diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/Converters/ConverterMigrationHelperTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/Converters/ConverterMigrationHelperTests.cs index c741076..97c2fca 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/Converters/ConverterMigrationHelperTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/Converters/ConverterMigrationHelperTests.cs @@ -10,23 +10,23 @@ namespace ReactiveUI.Binding.Tests.Bindings.Converters; /// public class ConverterMigrationHelperTests { - /// - /// The expected number of converters extracted when two are registered. - /// + /// Affinity ranking below . + private const int BelowDefaultAffinity = 3; + + /// The affinity a plain test converter reports unless a test needs a ranking. + private const int DefaultAffinity = 5; + + /// The expected number of converters extracted when two are registered. private const int ExpectedTwoConverters = 2; - /// - /// Verifies that ExtractConverters throws when resolver is null. - /// + /// Verifies that ExtractConverters throws when resolver is null. /// A task representing the asynchronous operation. [Test] public async Task ExtractConverters_ShouldThrowArgumentNullException_WhenResolverIsNull() => - await Assert.That(() => ConverterMigrationHelper.ExtractConverters(null!)) + await Assert.That(static () => ConverterMigrationHelper.ExtractConverters(null!)) .Throws(); - /// - /// Verifies that ExtractConverters returns empty lists when no converters registered. - /// + /// Verifies that ExtractConverters returns empty lists when no converters registered. /// A task representing the asynchronous operation. [Test] public async Task ExtractConverters_ShouldReturnEmptyLists_WhenNoConvertersRegistered() @@ -43,16 +43,14 @@ public async Task ExtractConverters_ShouldReturnEmptyLists_WhenNoConvertersRegis await Assert.That(setMethod).IsEmpty(); } - /// - /// Verifies that ExtractConverters extracts typed converters. - /// + /// Verifies that ExtractConverters extracts typed converters. /// A task representing the asynchronous operation. [Test] public async Task ExtractConverters_ShouldExtractTypedConverters() { // Arrange - var converter1 = new TestTypedConverter(5); - var converter2 = new TestTypedConverter(3); + var converter1 = new TestTypedConverter(DefaultAffinity); + var converter2 = new TestTypedConverter(BelowDefaultAffinity); var resolver = new TestDependencyResolver(); resolver.RegisterService(converter1); resolver.RegisterService(converter2); @@ -68,16 +66,14 @@ public async Task ExtractConverters_ShouldExtractTypedConverters() await Assert.That(setMethod).IsEmpty(); } - /// - /// Verifies that ExtractConverters extracts fallback converters. - /// + /// Verifies that ExtractConverters extracts fallback converters. /// A task representing the asynchronous operation. [Test] public async Task ExtractConverters_ShouldExtractFallbackConverters() { // Arrange - var converter1 = new TestFallbackConverter(5); - var converter2 = new TestFallbackConverter(3); + var converter1 = new TestFallbackConverter(DefaultAffinity); + var converter2 = new TestFallbackConverter(BelowDefaultAffinity); var resolver = new TestDependencyResolver(); resolver.RegisterService(converter1); resolver.RegisterService(converter2); @@ -93,16 +89,14 @@ public async Task ExtractConverters_ShouldExtractFallbackConverters() await Assert.That(setMethod).IsEmpty(); } - /// - /// Verifies that ExtractConverters extracts set-method converters. - /// + /// Verifies that ExtractConverters extracts set-method converters. /// A task representing the asynchronous operation. [Test] public async Task ExtractConverters_ShouldExtractSetMethodConverters() { // Arrange - var converter1 = new TestSetMethodConverter(5); - var converter2 = new TestSetMethodConverter(3); + var converter1 = new TestSetMethodConverter(DefaultAffinity); + var converter2 = new TestSetMethodConverter(BelowDefaultAffinity); var resolver = new TestDependencyResolver(); resolver.RegisterService(converter1); resolver.RegisterService(converter2); @@ -118,17 +112,15 @@ public async Task ExtractConverters_ShouldExtractSetMethodConverters() await Assert.That(setMethod).Contains(converter2); } - /// - /// Verifies that ExtractConverters extracts all converter types. - /// + /// Verifies that ExtractConverters extracts all converter types. /// A task representing the asynchronous operation. [Test] public async Task ExtractConverters_ShouldExtractAllConverterTypes() { // Arrange - var typedConverter = new TestTypedConverter(5); - var fallbackConverter = new TestFallbackConverter(3); - var setMethodConverter = new TestSetMethodConverter(2); + var typedConverter = new TestTypedConverter(DefaultAffinity); + var fallbackConverter = new TestFallbackConverter(BelowDefaultAffinity); + var setMethodConverter = new TestSetMethodConverter(ExpectedTwoConverters); var resolver = new TestDependencyResolver(); resolver.RegisterService(typedConverter); resolver.RegisterService(fallbackConverter); @@ -146,15 +138,13 @@ public async Task ExtractConverters_ShouldExtractAllConverterTypes() await Assert.That(setMethod).Contains(setMethodConverter); } - /// - /// Verifies that ExtractConverters filters out null converters. - /// + /// Verifies that ExtractConverters filters out null converters. /// A task representing the asynchronous operation. [Test] public async Task ExtractConverters_ShouldFilterOutNullConverters() { // Arrange - var converter = new TestTypedConverter(5); + var converter = new TestTypedConverter(DefaultAffinity); var resolver = new TestDependencyResolver(); resolver.RegisterService(converter); resolver.RegisterService(null!); @@ -167,9 +157,7 @@ public async Task ExtractConverters_ShouldFilterOutNullConverters() await Assert.That(typed).Contains(converter); } - /// - /// Verifies that ImportFrom throws when converter service is null. - /// + /// Verifies that ImportFrom throws when converter service is null. /// A task representing the asynchronous operation. [Test] public async Task ImportFrom_ShouldThrowArgumentNullException_WhenConverterServiceIsNull() @@ -182,9 +170,7 @@ await Assert.That(() => ((ConverterService)null!).ImportFrom(resolver)) .Throws(); } - /// - /// Verifies that ImportFrom throws when resolver is null. - /// + /// Verifies that ImportFrom throws when resolver is null. /// A task representing the asynchronous operation. [Test] public async Task ImportFrom_ShouldThrowArgumentNullException_WhenResolverIsNull() @@ -197,16 +183,14 @@ await Assert.That(() => service.ImportFrom(null!)) .Throws(); } - /// - /// Verifies that ImportFrom imports typed converters. - /// + /// Verifies that ImportFrom imports typed converters. /// A task representing the asynchronous operation. [Test] public async Task ImportFrom_ShouldImportTypedConverters() { // Arrange - var converter1 = new TestTypedConverter(5); - var converter2 = new TestTypedConverter(3); + var converter1 = new TestTypedConverter(DefaultAffinity); + var converter2 = new TestTypedConverter(BelowDefaultAffinity); var resolver = new TestDependencyResolver(); resolver.RegisterService(converter1); resolver.RegisterService(converter2); @@ -222,15 +206,13 @@ public async Task ImportFrom_ShouldImportTypedConverters() await Assert.That(result2).IsEqualTo(converter2); } - /// - /// Verifies that ImportFrom imports fallback converters. - /// + /// Verifies that ImportFrom imports fallback converters. /// A task representing the asynchronous operation. [Test] public async Task ImportFrom_ShouldImportFallbackConverters() { // Arrange - var converter = new TestFallbackConverter(5); + var converter = new TestFallbackConverter(DefaultAffinity); var resolver = new TestDependencyResolver(); resolver.RegisterService(converter); var service = new ConverterService(); @@ -243,15 +225,13 @@ public async Task ImportFrom_ShouldImportFallbackConverters() await Assert.That(result).IsEqualTo(converter); } - /// - /// Verifies that ImportFrom imports set-method converters. - /// + /// Verifies that ImportFrom imports set-method converters. /// A task representing the asynchronous operation. [Test] public async Task ImportFrom_ShouldImportSetMethodConverters() { // Arrange - var converter = new TestSetMethodConverter(5); + var converter = new TestSetMethodConverter(DefaultAffinity); var resolver = new TestDependencyResolver(); resolver.RegisterService(converter); var service = new ConverterService(); @@ -264,17 +244,15 @@ public async Task ImportFrom_ShouldImportSetMethodConverters() await Assert.That(result).IsEqualTo(converter); } - /// - /// Verifies that ImportFrom imports all converter types. - /// + /// Verifies that ImportFrom imports all converter types. /// A task representing the asynchronous operation. [Test] public async Task ImportFrom_ShouldImportAllConverterTypes() { // Arrange - var typedConverter = new TestTypedConverter(5); - var fallbackConverter = new TestFallbackConverter(3); - var setMethodConverter = new TestSetMethodConverter(2); + var typedConverter = new TestTypedConverter(DefaultAffinity); + var fallbackConverter = new TestFallbackConverter(BelowDefaultAffinity); + var setMethodConverter = new TestSetMethodConverter(ExpectedTwoConverters); var resolver = new TestDependencyResolver(); resolver.RegisterService(typedConverter); resolver.RegisterService(fallbackConverter); @@ -292,15 +270,13 @@ public async Task ImportFrom_ShouldImportAllConverterTypes() await Assert.That(setMethodResult).IsEqualTo(setMethodConverter); } - /// - /// Verifies that ImportFrom does not import null converters. - /// + /// Verifies that ImportFrom does not import null converters. /// A task representing the asynchronous operation. [Test] public async Task ImportFrom_ShouldNotImportNullConverters() { // Arrange - var converter = new TestTypedConverter(5); + var converter = new TestTypedConverter(DefaultAffinity); var resolver = new TestDependencyResolver(); resolver.RegisterService(converter); resolver.RegisterService(null!); @@ -314,19 +290,13 @@ public async Task ImportFrom_ShouldNotImportNullConverters() await Assert.That(result).IsEqualTo(converter); } - /// - /// Test dependency resolver for testing converter extraction. - /// + /// Test dependency resolver for testing converter extraction. private sealed class TestDependencyResolver : IReadonlyDependencyResolver { - /// - /// Registered services for resolution. - /// + /// Registered services for resolution. private readonly List _services = []; - /// - /// Registers a service instance for later resolution. - /// + /// Registers a service instance for later resolution. /// The service type to register. /// The service instance to register. public void RegisterService(T? service) => _services.Add(service!); @@ -338,46 +308,29 @@ private sealed class TestDependencyResolver : IReadonlyDependencyResolver public object? GetService(Type? serviceType, string? contract) => _services.FirstOrDefault(); /// - [SuppressMessage( - "Major Code Smell", - "S4018:Generic methods should provide type parameter for type inference", - Justification = "Type parameter is dictated by the implemented interface and is not inferable from the arguments.")] public T? GetService() => _services.OfType().FirstOrDefault(); /// - [SuppressMessage( - "Major Code Smell", - "S4018:Generic methods should provide type parameter for type inference", - Justification = "Type parameter is dictated by the implemented interface and is not inferable from the arguments.")] public T? GetService(string? contract) => _services.OfType().FirstOrDefault(); /// - public IEnumerable GetServices(Type? serviceType) => _services.Where(s => s is not null)!; + public IEnumerable GetServices(Type? serviceType) => _services.Where(static s => s is not null)!; /// public IEnumerable GetServices(Type? serviceType, string? contract) => - _services.Where(s => s is not null)!; + _services.Where(static s => s is not null)!; /// - [SuppressMessage( - "Major Code Smell", - "S4018:Generic methods should provide type parameter for type inference", - Justification = "Type parameter is dictated by the implemented interface and is not inferable from the arguments.")] public IEnumerable GetServices() => _services.OfType(); /// - [SuppressMessage( - "Major Code Smell", - "S4018:Generic methods should provide type parameter for type inference", - Justification = "Type parameter is dictated by the implemented interface and is not inferable from the arguments.")] public IEnumerable GetServices(string? contract) => _services.OfType(); } - /// - /// Test typed converter for testing purposes. - /// + /// Test typed converter for testing purposes. /// The source type for conversion. /// The target type for conversion. + /// The affinity this converter reports. private sealed class TestTypedConverter(int affinity) : BindingTypeConverter { /// @@ -391,9 +344,8 @@ public override bool TryConvert(TFrom? from, object? conversionHint, [NotNullWhe } } - /// - /// Test fallback converter for testing purposes. - /// + /// Test fallback converter for testing purposes. + /// The affinity this converter reports. private sealed class TestFallbackConverter(int affinity) : IBindingFallbackConverter { /// @@ -412,9 +364,8 @@ public bool TryConvert( } } - /// - /// Test set method converter for testing purposes. - /// + /// Test set method converter for testing purposes. + /// The affinity this converter reports. private sealed class TestSetMethodConverter(int affinity) : ISetMethodBindingConverter { /// diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/Converters/ConverterRegistryTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/Converters/ConverterRegistryTests.cs index e1ee7ce..ed234c1 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/Converters/ConverterRegistryTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/Converters/ConverterRegistryTests.cs @@ -10,38 +10,45 @@ namespace ReactiveUI.Binding.Tests.Bindings.Converters; /// public class ConverterRegistryTests { - /// - /// The number of concurrent read iterations in the thread-safety test. - /// + /// A negative affinity, which means the converter does not apply. + private const int NegativeAffinity = -5; + + /// The UTC offset, in hours, of the sample timestamp under test. + private const int OffsetHours = -5; + + /// The affinity a plain test converter reports unless a test needs a ranking. + private const int DefaultAffinity = 5; + + /// Affinity ranking above . + private const int AboveDefaultAffinity = 8; + + /// Affinity ranking that outranks every other converter registered in a test. + private const int HighAffinity = 10; + + /// The highest affinity used, for the converter a test expects to win outright. + private const int HighestAffinity = 100; + + /// The number of concurrent read iterations in the thread-safety test. private const int ConcurrentReadIterations = 100; - /// - /// The iteration index at which a concurrent write is interleaved. - /// + /// The iteration index at which a concurrent write is interleaved. private const int ConcurrentWriteIteration = 50; - /// - /// The expected number of converters after registering three. - /// + /// The expected number of converters after registering three. private const int ExpectedThreeConverters = 3; - /// - /// The expected number of converters after registering two. - /// + /// The expected number of converters after registering two. private const int ExpectedTwoConverters = 2; - /// - /// Verifies that the registry supports concurrent reads during registration. - /// This tests the lock-free snapshot pattern. - /// + /// Verifies that the registry supports concurrent reads during registration. This tests the lock-free snapshot pattern. /// A task representing the asynchronous operation. [Test] public async Task ConcurrentReads_DuringRegistration_ShouldBeThreadSafe() { // Arrange var registry = new BindingTypeConverterRegistry(); - var converter1 = new TestConverter(5); - var converter2 = new TestConverter(3); + var converter1 = new TestConverter(DefaultAffinity); + var converter2 = new TestConverter(ExpectedThreeConverters); registry.Register(converter1); var readTasks = new List>(); @@ -77,17 +84,15 @@ public async Task ConcurrentReads_DuringRegistration_ShouldBeThreadSafe() await Assert.That(finalCheck2).IsEqualTo(converter2); } - /// - /// Verifies that converters with negative affinity are ignored. - /// + /// Verifies that converters with negative affinity are ignored. /// A task representing the asynchronous operation. [Test] public async Task ConverterWithNegativeAffinity_ShouldBeIgnored() { // Arrange var registry = new BindingTypeConverterRegistry(); - var negativeAffinity = new TestConverter(-5); - var validAffinity = new TestConverter(2); + var negativeAffinity = new TestConverter(NegativeAffinity); + var validAffinity = new TestConverter(ExpectedTwoConverters); // Act registry.Register(negativeAffinity); @@ -99,9 +104,7 @@ public async Task ConverterWithNegativeAffinity_ShouldBeIgnored() await Assert.That(selected).IsEqualTo(validAffinity); } - /// - /// Verifies that converters with affinity 0 are ignored. - /// + /// Verifies that converters with affinity 0 are ignored. /// A task representing the asynchronous operation. [Test] public async Task ConverterWithZeroAffinity_ShouldBeIgnored() @@ -109,7 +112,7 @@ public async Task ConverterWithZeroAffinity_ShouldBeIgnored() // Arrange var registry = new BindingTypeConverterRegistry(); var zeroAffinity = new TestConverter(0); - var validAffinity = new TestConverter(2); + var validAffinity = new TestConverter(ExpectedTwoConverters); // Act registry.Register(zeroAffinity); @@ -121,9 +124,7 @@ public async Task ConverterWithZeroAffinity_ShouldBeIgnored() await Assert.That(selected).IsEqualTo(validAffinity); } - /// - /// Verifies that an empty registry returns null. - /// + /// Verifies that an empty registry returns null. /// A task representing the asynchronous operation. [Test] public async Task EmptyRegistry_ShouldReturnNull() @@ -138,17 +139,15 @@ public async Task EmptyRegistry_ShouldReturnNull() await Assert.That(result).IsNull(); } - /// - /// Verifies that fallback converter registry works correctly. - /// + /// Verifies that fallback converter registry works correctly. /// A task representing the asynchronous operation. [Test] public async Task FallbackRegistry_ShouldSelectHighestAffinity() { // Arrange var registry = new BindingFallbackConverterRegistry(); - var lowAffinity = new TestFallbackConverter(2); - var highAffinity = new TestFallbackConverter(10); + var lowAffinity = new TestFallbackConverter(ExpectedTwoConverters); + var highAffinity = new TestFallbackConverter(HighAffinity); // Act registry.Register(lowAffinity); @@ -160,18 +159,16 @@ public async Task FallbackRegistry_ShouldSelectHighestAffinity() await Assert.That(selected).IsEqualTo(highAffinity); } - /// - /// Verifies that GetAllConverters returns all registered converters. - /// + /// Verifies that GetAllConverters returns all registered converters. /// A task representing the asynchronous operation. [Test] public async Task GetAllConverters_ShouldReturnAllRegistered() { // Arrange var registry = new BindingTypeConverterRegistry(); - var converter1 = new TestConverter(5); - var converter2 = new TestConverter(3); - var converter3 = new TestConverter(2); + var converter1 = new TestConverter(DefaultAffinity); + var converter2 = new TestConverter(ExpectedThreeConverters); + var converter3 = new TestConverter(ExpectedTwoConverters); // Act registry.Register(converter1); @@ -197,9 +194,9 @@ public async Task MultipleConverters_ShouldSelectHighestAffinity() { // Arrange var registry = new BindingTypeConverterRegistry(); - var lowAffinity = new TestConverter(2); - var mediumAffinity = new TestConverter(5); - var highAffinity = new TestConverter(10); + var lowAffinity = new TestConverter(ExpectedTwoConverters); + var mediumAffinity = new TestConverter(DefaultAffinity); + var highAffinity = new TestConverter(HighAffinity); // Act - register in random order registry.Register(mediumAffinity); @@ -212,16 +209,14 @@ public async Task MultipleConverters_ShouldSelectHighestAffinity() await Assert.That(selected).IsEqualTo(highAffinity); } - /// - /// Verifies that requesting a non-existent type pair returns null. - /// + /// Verifies that requesting a non-existent type pair returns null. /// A task representing the asynchronous operation. [Test] public async Task NonExistentTypePair_ShouldReturnNull() { // Arrange var registry = new BindingTypeConverterRegistry(); - var converter = new TestConverter(5); + var converter = new TestConverter(DefaultAffinity); registry.Register(converter); // Act @@ -231,16 +226,14 @@ public async Task NonExistentTypePair_ShouldReturnNull() await Assert.That(result).IsNull(); } - /// - /// Verifies that a registered converter can be retrieved. - /// + /// Verifies that a registered converter can be retrieved. /// A task representing the asynchronous operation. [Test] public async Task Register_AndRetrieve_ShouldReturnConverter() { // Arrange var registry = new BindingTypeConverterRegistry(); - var converter = new TestConverter(5); + var converter = new TestConverter(DefaultAffinity); // Act registry.Register(converter); @@ -251,17 +244,15 @@ public async Task Register_AndRetrieve_ShouldReturnConverter() await Assert.That(retrieved).IsEqualTo(converter); } - /// - /// Verifies that set-method converter registry works correctly. - /// + /// Verifies that set-method converter registry works correctly. /// A task representing the asynchronous operation. [Test] public async Task SetMethodRegistry_ShouldSelectHighestAffinity() { // Arrange var registry = new SetMethodBindingConverterRegistry(); - var lowAffinity = new TestSetMethodConverter(2); - var highAffinity = new TestSetMethodConverter(8); + var lowAffinity = new TestSetMethodConverter(ExpectedTwoConverters); + var highAffinity = new TestSetMethodConverter(AboveDefaultAffinity); // Act registry.Register(lowAffinity); @@ -303,9 +294,7 @@ public async Task SetMethodRegistry_Empty_GetAllConverters_ReturnsEmpty() await Assert.That(result.Count()).IsEqualTo(0); } - /// - /// Verifies that SetMethodBindingConverterRegistry.Register throws ArgumentNullException for null converter. - /// + /// Verifies that SetMethodBindingConverterRegistry.Register throws ArgumentNullException for null converter. /// A task representing the asynchronous operation. [Test] public async Task SetMethodRegistry_Register_Null_ThrowsArgumentNullException() @@ -317,16 +306,14 @@ public async Task SetMethodRegistry_Register_Null_ThrowsArgumentNullException() await Assert.That(action).ThrowsExactly(); } - /// - /// Verifies that SetMethodBindingConverterRegistry.GetAllConverters returns all registered converters. - /// + /// Verifies that SetMethodBindingConverterRegistry.GetAllConverters returns all registered converters. /// A task representing the asynchronous operation. [Test] public async Task SetMethodRegistry_GetAllConverters_ReturnsAllRegistered() { var registry = new SetMethodBindingConverterRegistry(); - var converter1 = new TestSetMethodConverter(5); - var converter2 = new TestSetMethodConverter(3); + var converter1 = new TestSetMethodConverter(DefaultAffinity); + var converter2 = new TestSetMethodConverter(ExpectedThreeConverters); registry.Register(converter1); registry.Register(converter2); @@ -367,11 +354,10 @@ public async Task FallbackRegistry_Fresh_GetAllConverters_ReturnsEmpty() await Assert.That(result.Count()).IsEqualTo(0); } - /// - /// Test typed converter for registry tests with configurable affinity. - /// + /// Test typed converter for registry tests with configurable affinity. /// The source type for conversion. /// The target type for conversion. + /// The affinity this converter reports. private sealed class TestConverter(int affinity) : BindingTypeConverter { /// @@ -385,9 +371,8 @@ public override bool TryConvert(TFrom? from, object? conversionHint, [NotNullWhe } } - /// - /// Test fallback converter for registry tests with configurable affinity. - /// + /// Test fallback converter for registry tests with configurable affinity. + /// The affinity this converter reports. private sealed class TestFallbackConverter(int baseAffinity) : IBindingFallbackConverter { /// @@ -412,9 +397,8 @@ public bool TryConvert( } } - /// - /// Test set-method converter for registry tests with configurable affinity. - /// + /// Test set-method converter for registry tests with configurable affinity. + /// The affinity this converter reports. private sealed class TestSetMethodConverter(int baseAffinity) : ISetMethodBindingConverter { /// diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/Converters/ConverterServiceIntegrationTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/Converters/ConverterServiceIntegrationTests.cs index ec033af..6003ab6 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/Converters/ConverterServiceIntegrationTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/Converters/ConverterServiceIntegrationTests.cs @@ -10,9 +10,25 @@ namespace ReactiveUI.Binding.Tests.Bindings.Converters; /// public class ConverterServiceIntegrationTests { - /// - /// Verifies that all three registries are accessible. - /// + /// The lowest affinity ranking used in these tests. + private const int LowAffinity = 2; + + /// Affinity ranking below . + private const int BelowDefaultAffinity = 3; + + /// The affinity a plain test converter reports unless a test needs a ranking. + private const int DefaultAffinity = 5; + + /// Affinity ranking above . + private const int AboveDefaultAffinity = 8; + + /// Affinity ranking that outranks every other converter registered in a test. + private const int HighAffinity = 10; + + /// The highest affinity used, for the converter a test expects to win outright. + private const int HighestAffinity = 100; + + /// Verifies that all three registries are accessible. /// A task representing the asynchronous operation. [Test] public async Task ConverterService_ShouldExposeAllRegistries() @@ -26,17 +42,15 @@ public async Task ConverterService_ShouldExposeAllRegistries() await Assert.That(service.SetMethodConverters).IsNotNull(); } - /// - /// Verifies that custom converters with high affinity can override defaults. - /// + /// Verifies that custom converters with high affinity can override defaults. /// A task representing the asynchronous operation. [Test] public async Task CustomHighAffinityConverter_ShouldOverrideDefault() { // Arrange var service = new ConverterService(); - var defaultConverter = new TestTypedConverter(2); - var customConverter = new TestTypedConverter(100); + var defaultConverter = new TestTypedConverter(LowAffinity); + var customConverter = new TestTypedConverter(HighestAffinity); service.TypedConverters.Register(defaultConverter); service.TypedConverters.Register(customConverter); @@ -48,17 +62,15 @@ public async Task CustomHighAffinityConverter_ShouldOverrideDefault() await Assert.That(result).IsEqualTo(customConverter); } - /// - /// Verifies that fallback converters are used when no typed converter matches. - /// + /// Verifies that fallback converters are used when no typed converter matches. /// A task representing the asynchronous operation. [Test] public async Task FallbackConverter_ShouldBeUsedWhenNoTypedMatch() { // Arrange var service = new ConverterService(); - var typedConverter = new TestTypedConverter(5); - var fallbackConverter = new TestFallbackConverter(3); + var typedConverter = new TestTypedConverter(DefaultAffinity); + var fallbackConverter = new TestFallbackConverter(BelowDefaultAffinity); service.TypedConverters.Register(typedConverter); service.FallbackConverters.Register(fallbackConverter); @@ -70,18 +82,16 @@ public async Task FallbackConverter_ShouldBeUsedWhenNoTypedMatch() await Assert.That(result).IsEqualTo(fallbackConverter); } - /// - /// Verifies that the highest affinity fallback converter is selected. - /// + /// Verifies that the highest affinity fallback converter is selected. /// A task representing the asynchronous operation. [Test] public async Task MultipleFallbackConverters_ShouldSelectHighestAffinity() { // Arrange var service = new ConverterService(); - var lowAffinity = new TestFallbackConverter(2); - var mediumAffinity = new TestFallbackConverter(5); - var highAffinity = new TestFallbackConverter(10); + var lowAffinity = new TestFallbackConverter(LowAffinity); + var mediumAffinity = new TestFallbackConverter(DefaultAffinity); + var highAffinity = new TestFallbackConverter(HighAffinity); service.FallbackConverters.Register(mediumAffinity); service.FallbackConverters.Register(lowAffinity); @@ -94,16 +104,14 @@ public async Task MultipleFallbackConverters_ShouldSelectHighestAffinity() await Assert.That(result).IsEqualTo(highAffinity); } - /// - /// Verifies that null is returned when no converter matches. - /// + /// Verifies that null is returned when no converter matches. /// A task representing the asynchronous operation. [Test] public async Task NoConverter_ShouldReturnNull() { // Arrange var service = new ConverterService(); - var converter = new TestTypedConverter(5); + var converter = new TestTypedConverter(DefaultAffinity); service.TypedConverters.Register(converter); // Act @@ -113,9 +121,7 @@ public async Task NoConverter_ShouldReturnNull() await Assert.That(result).IsNull(); } - /// - /// Verifies end-to-end integration with real converters. - /// + /// Verifies end-to-end integration with real converters. /// A task representing the asynchronous operation. [Test] public async Task RealConverters_ShouldResolveCorrectly() @@ -139,16 +145,14 @@ public async Task RealConverters_ShouldResolveCorrectly() await Assert.That(result2).IsEqualTo(stringToInt); } - /// - /// Verifies that BindingConverters.Current works after being set. - /// + /// Verifies that BindingConverters.Current works after being set. /// A task representing the asynchronous operation. [Test] public async Task BindingConverters_CurrentShouldBeAccessible() { // Arrange var service = new ConverterService(); - var converter = new TestTypedConverter(5); + var converter = new TestTypedConverter(DefaultAffinity); service.TypedConverters.Register(converter); // Act @@ -162,16 +166,14 @@ public async Task BindingConverters_CurrentShouldBeAccessible() BindingConverters.SetService(new()); } - /// - /// Verifies that set-method converters can be registered and retrieved. - /// + /// Verifies that set-method converters can be registered and retrieved. /// A task representing the asynchronous operation. [Test] public async Task SetMethodConverter_ShouldBeRetrievable() { // Arrange var service = new ConverterService(); - var setMethodConverter = new TestSetMethodConverter(8); + var setMethodConverter = new TestSetMethodConverter(AboveDefaultAffinity); service.SetMethodConverters.Register(setMethodConverter); @@ -182,17 +184,15 @@ public async Task SetMethodConverter_ShouldBeRetrievable() await Assert.That(result).IsEqualTo(setMethodConverter); } - /// - /// Verifies that typed converters are selected before fallback converters. - /// + /// Verifies that typed converters are selected before fallback converters. /// A task representing the asynchronous operation. [Test] public async Task TypedConverter_ShouldBePreferredOverFallback() { // Arrange var service = new ConverterService(); - var typedConverter = new TestTypedConverter(2); - var fallbackConverter = new TestFallbackConverter(10); // Higher affinity but should lose to typed + var typedConverter = new TestTypedConverter(LowAffinity); + var fallbackConverter = new TestFallbackConverter(HighAffinity); // Higher affinity but should lose to typed service.TypedConverters.Register(typedConverter); service.FallbackConverters.Register(fallbackConverter); @@ -204,9 +204,7 @@ public async Task TypedConverter_ShouldBePreferredOverFallback() await Assert.That(result).IsEqualTo(typedConverter); } - /// - /// Verifies that converters with affinity 0 are ignored in resolution. - /// + /// Verifies that converters with affinity 0 are ignored in resolution. /// A task representing the asynchronous operation. [Test] public async Task ZeroAffinityConverter_ShouldBeIgnoredInResolution() @@ -214,7 +212,7 @@ public async Task ZeroAffinityConverter_ShouldBeIgnoredInResolution() // Arrange var service = new ConverterService(); var zeroAffinity = new TestTypedConverter(0); - var validAffinity = new TestTypedConverter(2); + var validAffinity = new TestTypedConverter(LowAffinity); service.TypedConverters.Register(zeroAffinity); service.TypedConverters.Register(validAffinity); @@ -226,9 +224,8 @@ public async Task ZeroAffinityConverter_ShouldBeIgnoredInResolution() await Assert.That(result).IsEqualTo(validAffinity); } - /// - /// Test fallback converter for integration testing with configurable affinity. - /// + /// Test fallback converter for integration testing with configurable affinity. + /// The affinity this converter reports. private sealed class TestFallbackConverter(int baseAffinity) : IBindingFallbackConverter { /// @@ -253,9 +250,8 @@ public bool TryConvert( } } - /// - /// Test set-method converter for integration testing with configurable affinity. - /// + /// Test set-method converter for integration testing with configurable affinity. + /// The affinity this converter reports. private sealed class TestSetMethodConverter(int baseAffinity) : ISetMethodBindingConverter { /// @@ -265,11 +261,10 @@ private sealed class TestSetMethodConverter(int baseAffinity) : ISetMethodBindin public object? PerformSet(object? toTarget, object? newValue, object?[]? arguments) => newValue; } - /// - /// Test typed converter for integration testing with configurable affinity. - /// + /// Test typed converter for integration testing with configurable affinity. /// The source type for conversion. /// The target type for conversion. + /// The affinity this converter reports. private sealed class TestTypedConverter(int affinity) : BindingTypeConverter { /// diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/ReactiveBindingTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/ReactiveBindingTests.cs index 550a641..d479ff1 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/ReactiveBindingTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/ReactiveBindingTests.cs @@ -2,22 +2,20 @@ // ReactiveUI Association Incorporated licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System.Runtime.CompilerServices; + namespace ReactiveUI.Binding.Tests.Bindings; -/// -/// Tests for . -/// +/// Tests for . public class ReactiveBindingTests { - /// - /// Verifies that Dispose disposes the underlying subscription. - /// + /// Verifies that Dispose disposes the underlying subscription. /// A task representing the asynchronous test operation. [Test] public async Task Dispose_DisposesSubscription() { - var disposed = false; - var subscription = Disposable.Create(() => disposed = true); + var disposed = new StrongBox(false); + var subscription = Disposable.Create(disposed, static state => state.Value = true); var view = new FakeView(); var changed = Observable.Empty(); @@ -29,18 +27,16 @@ public async Task Dispose_DisposesSubscription() binding.Dispose(); - await Assert.That(disposed).IsTrue(); + await Assert.That(disposed.Value).IsTrue(); } - /// - /// Verifies that double-disposal does not throw. - /// + /// Verifies that double-disposal does not throw. /// A task representing the asynchronous test operation. [Test] public async Task Dispose_Twice_DoesNotThrow() { - var disposeCount = 0; - var subscription = Disposable.Create(() => disposeCount++); + var disposeCount = new StrongBox(0); + var subscription = Disposable.Create(disposeCount, static state => state.Value++); var view = new FakeView(); var changed = Observable.Empty(); @@ -53,12 +49,10 @@ public async Task Dispose_Twice_DoesNotThrow() binding.Dispose(); binding.Dispose(); - await Assert.That(disposeCount).IsEqualTo(1); + await Assert.That(disposeCount.Value).IsEqualTo(1); } - /// - /// Verifies that constructor values are returned by properties. - /// + /// Verifies that constructor values are returned by properties. /// A task representing the asynchronous test operation. [Test] public async Task Properties_ReturnConstructorValues() @@ -80,9 +74,7 @@ public async Task Properties_ReturnConstructorValues() await Assert.That(binding.ViewExpression).IsNull(); } - /// - /// A minimal fake view for testing. - /// + /// A minimal fake view for testing. private sealed class FakeView : IViewFor { /// diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/BindingTypeConverterBaseTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/BindingTypeConverterBaseTests.cs index b604b9d..5bf2604 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/BindingTypeConverterBaseTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/BindingTypeConverterBaseTests.cs @@ -11,14 +11,16 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; /// public class BindingTypeConverterBaseTests { - /// - /// Integer value parsed from the string "42" in conversion tests. - /// + /// The conversion hint passed to the converter, which selects the output format. + private const int ConversionHint = 3; + + /// The value fed into the converter under test. + private const int SourceValue = 5; + + /// Integer value parsed from the string "42" in conversion tests. private const int ParsedInteger = 42; - /// - /// Integer value parsed from the string "100" in the boxing test. - /// + /// Integer value parsed from the string "100" in the boxing test. private const int BoxedInteger = 100; /// @@ -47,7 +49,7 @@ public async Task TryConvertTyped_WrongInputType_ReturnsFalse() { var converter = new StringToIntegerTypeConverter(); - var result = converter.TryConvertTyped(42, null, out var output); + var result = converter.TryConvertTyped(ParsedInteger, null, out var output); await Assert.That(result).IsFalse(); await Assert.That(output).IsNull(); @@ -85,16 +87,14 @@ public async Task TryConvertTyped_ValidInput_ReturnsTrue() await Assert.That(output).IsEqualTo(ParsedInteger); } - /// - /// Verifies TryConvertTyped succeeds when converting from a value type to a reference type. - /// + /// Verifies TryConvertTyped succeeds when converting from a value type to a reference type. /// A task representing the asynchronous test operation. [Test] public async Task TryConvertTyped_ValueTypeToReferenceType_Succeeds() { var converter = new IntegerToStringTypeConverter(); - var result = converter.TryConvertTyped(42, null, out var output); + var result = converter.TryConvertTyped(ParsedInteger, null, out var output); await Assert.That(result).IsTrue(); await Assert.That(output).IsEqualTo("42"); @@ -183,24 +183,20 @@ public async Task TryConvertTyped_NullInput_ReferenceTypeSourceTryConvertFails_R await Assert.That(output).IsNull(); } - /// - /// Verifies TryConvertTyped passes conversionHint through to TryConvert. - /// + /// Verifies TryConvertTyped passes conversionHint through to TryConvert. /// A task representing the asynchronous test operation. [Test] public async Task TryConvertTyped_WithConversionHint_PassesThroughToTryConvert() { var converter = new IntegerToStringTypeConverter(); - var result = converter.TryConvertTyped(5, 3, out var output); + var result = converter.TryConvertTyped(SourceValue, ConversionHint, out var output); await Assert.That(result).IsTrue(); await Assert.That(output).IsEqualTo("005"); } - /// - /// Verifies TryConvertTyped correctly boxes value type results. - /// + /// Verifies TryConvertTyped correctly boxes value type results. /// A task representing the asynchronous test operation. [Test] public async Task TryConvertTyped_ValueTypeResult_IsBoxedCorrectly() @@ -214,9 +210,7 @@ public async Task TryConvertTyped_ValueTypeResult_IsBoxedCorrectly() await Assert.That(output).IsEqualTo(BoxedInteger); } - /// - /// Verifies that FromType returns the correct type for a generic converter. - /// + /// Verifies that FromType returns the correct type for a generic converter. /// A task representing the asynchronous test operation. [Test] public async Task FromType_ReturnsCorrectGenericType() @@ -226,9 +220,7 @@ public async Task FromType_ReturnsCorrectGenericType() await Assert.That(converter.FromType).IsEqualTo(typeof(string)); } - /// - /// Verifies that ToType returns the correct type for a generic converter. - /// + /// Verifies that ToType returns the correct type for a generic converter. /// A task representing the asynchronous test operation. [Test] public async Task ToType_ReturnsCorrectGenericType() @@ -405,9 +397,7 @@ public override bool TryConvert(int? from, object? conversionHint, [MaybeNullWhe } } - /// - /// A converter from string to string that accepts null input and converts it to "(null)". - /// + /// A converter from string to string that accepts null input and converts it to "(null)". private sealed class NullAcceptingStringToStringConverter : BindingTypeConverter { /// @@ -421,9 +411,7 @@ public override bool TryConvert(string? from, object? conversionHint, [MaybeNull } } - /// - /// A converter from string to string that returns null for null input (for nullable TTo). - /// + /// A converter from string to string that returns null for null input (for nullable TTo). private sealed class NullToNullStringConverter : BindingTypeConverter { /// diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/BooleanToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/BooleanToStringTypeConverterTests.cs index fcb3001..200be5d 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/BooleanToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/BooleanToStringTypeConverterTests.cs @@ -4,19 +4,13 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting booleans to strings. -/// +/// Tests for converting booleans to strings. public class BooleanToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,9 +20,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert True ReturnsTrue. - /// + /// Verifies TryConvert True ReturnsTrue. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_True_ReturnsTrue() @@ -41,9 +33,7 @@ public async Task TryConvert_True_ReturnsTrue() await Assert.That(output).IsEqualTo("True"); } - /// - /// Verifies TryConvert False ReturnsFalse. - /// + /// Verifies TryConvert False ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_False_ReturnsFalse() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/ByteToNullableByteTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/ByteToNullableByteTypeConverterTests.cs index e6b7b4c..f8498bc 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/ByteToNullableByteTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/ByteToNullableByteTypeConverterTests.cs @@ -4,24 +4,16 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting byte to nullable byte. -/// +/// Tests for converting byte to nullable byte. public class ByteToNullableByteTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Sample byte value used for conversion round-trips. - /// + /// Sample byte value used for conversion round-trips. private const byte SampleByte = 42; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -31,9 +23,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert AlwaysSucceeds. - /// + /// Verifies TryConvert AlwaysSucceeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_AlwaysSucceeds() @@ -47,9 +37,7 @@ public async Task TryConvert_AlwaysSucceeds() await Assert.That(output).IsEqualTo((byte?)SampleByte); } - /// - /// Verifies FromType ReturnsByte. - /// + /// Verifies FromType ReturnsByte. /// A task representing the asynchronous operation. [Test] public async Task FromType_ReturnsByte() @@ -58,9 +46,7 @@ public async Task FromType_ReturnsByte() await Assert.That(converter.FromType).IsEqualTo(typeof(byte)); } - /// - /// Verifies ToType ReturnsByteNullable. - /// + /// Verifies ToType ReturnsByteNullable. /// A task representing the asynchronous operation. [Test] public async Task ToType_ReturnsByteNullable() @@ -69,9 +55,7 @@ public async Task ToType_ReturnsByteNullable() await Assert.That(converter.ToType).IsEqualTo(typeof(byte?)); } - /// - /// Verifies TryConvertTyped WithValidValue ReturnsTrueAndOutput. - /// + /// Verifies TryConvertTyped WithValidValue ReturnsTrueAndOutput. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithValidValue_ReturnsTrueAndOutput() @@ -85,9 +69,7 @@ public async Task TryConvertTyped_WithValidValue_ReturnsTrueAndOutput() await Assert.That(result).IsEqualTo((byte?)SampleByte); } - /// - /// Verifies TryConvertTyped WithNullValue ReturnsFalse. - /// + /// Verifies TryConvertTyped WithNullValue ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithNullValue_ReturnsFalse() @@ -100,9 +82,7 @@ public async Task TryConvertTyped_WithNullValue_ReturnsFalse() await Assert.That(result).IsNull(); } - /// - /// Verifies TryConvertTyped WithInvalidType ReturnsFalse. - /// + /// Verifies TryConvertTyped WithInvalidType ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithInvalidType_ReturnsFalse() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/ByteToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/ByteToStringTypeConverterTests.cs index 91b333e..6a589f7 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/ByteToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/ByteToStringTypeConverterTests.cs @@ -4,19 +4,16 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for the type converter. -/// +/// Tests for the type converter. public class ByteToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// The conversion hint passed to the converter, which selects the output format. + private const int ConversionHint = 3; + + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,9 +23,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert ByteToString Succeeds. - /// + /// Verifies TryConvert ByteToString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_ByteToString_Succeeds() @@ -42,9 +37,7 @@ public async Task TryConvert_ByteToString_Succeeds() await Assert.That(output).IsEqualTo("123"); } - /// - /// Verifies TryConvert MaxValue Succeeds. - /// + /// Verifies TryConvert MaxValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MaxValue_Succeeds() @@ -58,9 +51,7 @@ public async Task TryConvert_MaxValue_Succeeds() await Assert.That(output).IsEqualTo("255"); } - /// - /// Verifies TryConvert MinValue Succeeds. - /// + /// Verifies TryConvert MinValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MinValue_Succeeds() @@ -74,9 +65,7 @@ public async Task TryConvert_MinValue_Succeeds() await Assert.That(output).IsEqualTo("0"); } - /// - /// Verifies TryConvert WithConversionHint FormatsCorrectly. - /// + /// Verifies TryConvert WithConversionHint FormatsCorrectly. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithConversionHint_FormatsCorrectly() @@ -84,15 +73,13 @@ public async Task TryConvert_WithConversionHint_FormatsCorrectly() var converter = new ByteToStringTypeConverter(); const byte value = 5; - var result = converter.TryConvert(value, 3, out var output); + var result = converter.TryConvert(value, ConversionHint, out var output); await Assert.That(result).IsTrue(); await Assert.That(output).IsEqualTo("005"); } - /// - /// Verifies TryConvert with a string format hint formats correctly. - /// + /// Verifies TryConvert with a string format hint formats correctly. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithStringFormatHint_FormatsCorrectly() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/DateOnlyToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/DateOnlyToStringTypeConverterTests.cs index 4f6cbed..93f5f89 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/DateOnlyToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/DateOnlyToStringTypeConverterTests.cs @@ -5,19 +5,19 @@ #if NET6_0_OR_GREATER namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting DateOnly to strings. -/// +/// Tests for converting DateOnly to strings. public class DateOnlyToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Year component of the sample date used across the conversion round-trips. + private const int SampleYear = 2_024; + + /// Day component of the sample date used across the conversion round-trips. + private const int SampleDay = 15; + + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -27,15 +27,13 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert DateOnly Succeeds. - /// + /// Verifies TryConvert DateOnly Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_DateOnly_Succeeds() { var converter = new DateOnlyToStringTypeConverter(); - var value = new DateOnly(2_024, 1, 15); + var value = new DateOnly(SampleYear, 1, SampleDay); var result = converter.TryConvert(value, null, out var output); @@ -43,9 +41,7 @@ public async Task TryConvert_DateOnly_Succeeds() await Assert.That(output).IsEqualTo(value.ToString()); } - /// - /// Verifies TryConvert MinValue Succeeds. - /// + /// Verifies TryConvert MinValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MinValue_Succeeds() @@ -59,9 +55,7 @@ public async Task TryConvert_MinValue_Succeeds() await Assert.That(output).IsEqualTo(DateOnly.MinValue.ToString()); } - /// - /// Verifies TryConvert MaxValue Succeeds. - /// + /// Verifies TryConvert MaxValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MaxValue_Succeeds() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/DateTimeOffsetToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/DateTimeOffsetToStringTypeConverterTests.cs index c8abb89..823ee5b 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/DateTimeOffsetToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/DateTimeOffsetToStringTypeConverterTests.cs @@ -4,19 +4,16 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting DateTimeOffset to strings. -/// +/// Tests for converting DateTimeOffset to strings. public class DateTimeOffsetToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// The UTC offset, in hours, of the sample timestamp under test. + private const int OffsetHours = -5; + + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,15 +23,13 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert DateTimeOffset Succeeds. - /// + /// Verifies TryConvert DateTimeOffset Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_DateTimeOffset_Succeeds() { var converter = new DateTimeOffsetToStringTypeConverter(); - var value = new DateTimeOffset(2_024, 1, 15, 10, 30, 45, TimeSpan.FromHours(-5)); + var value = new DateTimeOffset(2_024, 1, 15, 10, 30, 45, TimeSpan.FromHours(OffsetHours)); var result = converter.TryConvert(value, null, out var output); @@ -42,9 +37,7 @@ public async Task TryConvert_DateTimeOffset_Succeeds() await Assert.That(output).IsEqualTo(value.ToString()); } - /// - /// Verifies TryConvert MinValue Succeeds. - /// + /// Verifies TryConvert MinValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MinValue_Succeeds() @@ -58,9 +51,7 @@ public async Task TryConvert_MinValue_Succeeds() await Assert.That(output).IsEqualTo(DateTimeOffset.MinValue.ToString()); } - /// - /// Verifies TryConvert MaxValue Succeeds. - /// + /// Verifies TryConvert MaxValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MaxValue_Succeeds() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/DateTimeToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/DateTimeToStringTypeConverterTests.cs index c070595..07d2bc3 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/DateTimeToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/DateTimeToStringTypeConverterTests.cs @@ -6,20 +6,13 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting DateTime to strings. -/// -[SuppressMessage("Major Code Smell", "S6566:Use \"DateTimeOffset\" instead of \"DateTime\"", Justification = "Tests focused on DateTime.")] +/// Tests for converting DateTime to strings. public class DateTimeToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -29,9 +22,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert DateTime Succeeds. - /// + /// Verifies TryConvert DateTime Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_DateTime_Succeeds() @@ -45,9 +36,7 @@ public async Task TryConvert_DateTime_Succeeds() await Assert.That(output).IsEqualTo(value.ToString(CultureInfo.CurrentCulture)); } - /// - /// Verifies TryConvert MinValue Succeeds. - /// + /// Verifies TryConvert MinValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MinValue_Succeeds() @@ -61,9 +50,7 @@ public async Task TryConvert_MinValue_Succeeds() await Assert.That(output).IsEqualTo(DateTime.MinValue.ToString(CultureInfo.CurrentCulture)); } - /// - /// Verifies TryConvert MaxValue Succeeds. - /// + /// Verifies TryConvert MaxValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MaxValue_Succeeds() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/DecimalToNullableDecimalTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/DecimalToNullableDecimalTypeConverterTests.cs index dc7acac..c0e606d 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/DecimalToNullableDecimalTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/DecimalToNullableDecimalTypeConverterTests.cs @@ -4,29 +4,19 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting decimal to nullable decimal. -/// +/// Tests for converting decimal to nullable decimal. public class DecimalToNullableDecimalTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Sample decimal value used for precise conversion checks. - /// - private const decimal SampleDecimal = 123.456789m; + /// Sample decimal value used for precise conversion checks. + private const decimal SampleDecimal = 123.456789M; - /// - /// Sample rounded decimal value used for conversion checks. - /// - private const decimal RoundedDecimal = 42.5m; + /// Sample rounded decimal value used for conversion checks. + private const decimal RoundedDecimal = 42.5M; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -36,15 +26,13 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert AlwaysSucceeds. - /// + /// Verifies TryConvert AlwaysSucceeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_AlwaysSucceeds() { var converter = new DecimalToNullableDecimalTypeConverter(); - const decimal value = 123.456789m; + const decimal value = 123.456789M; var result = converter.TryConvert(value, null, out var output); @@ -52,9 +40,7 @@ public async Task TryConvert_AlwaysSucceeds() await Assert.That(output).IsEqualTo((decimal?)SampleDecimal); } - /// - /// Verifies FromType ReturnsDecimal. - /// + /// Verifies FromType ReturnsDecimal. /// A task representing the asynchronous operation. [Test] public async Task FromType_ReturnsDecimal() @@ -63,9 +49,7 @@ public async Task FromType_ReturnsDecimal() await Assert.That(converter.FromType).IsEqualTo(typeof(decimal)); } - /// - /// Verifies ToType ReturnsDecimalNullable. - /// + /// Verifies ToType ReturnsDecimalNullable. /// A task representing the asynchronous operation. [Test] public async Task ToType_ReturnsDecimalNullable() @@ -74,15 +58,13 @@ public async Task ToType_ReturnsDecimalNullable() await Assert.That(converter.ToType).IsEqualTo(typeof(decimal?)); } - /// - /// Verifies TryConvertTyped WithValidValue ReturnsTrueAndOutput. - /// + /// Verifies TryConvertTyped WithValidValue ReturnsTrueAndOutput. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithValidValue_ReturnsTrueAndOutput() { var converter = new DecimalToNullableDecimalTypeConverter(); - const decimal value = 42.5m; + const decimal value = 42.5M; var success = converter.TryConvertTyped(value, null, out var result); @@ -90,9 +72,7 @@ public async Task TryConvertTyped_WithValidValue_ReturnsTrueAndOutput() await Assert.That(result).IsEqualTo((decimal?)RoundedDecimal); } - /// - /// Verifies TryConvertTyped WithNullValue ReturnsFalse. - /// + /// Verifies TryConvertTyped WithNullValue ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithNullValue_ReturnsFalse() @@ -105,9 +85,7 @@ public async Task TryConvertTyped_WithNullValue_ReturnsFalse() await Assert.That(result).IsNull(); } - /// - /// Verifies TryConvertTyped WithInvalidType ReturnsFalse. - /// + /// Verifies TryConvertTyped WithInvalidType ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithInvalidType_ReturnsFalse() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/DecimalToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/DecimalToStringTypeConverterTests.cs index 061a873..a0ffb65 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/DecimalToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/DecimalToStringTypeConverterTests.cs @@ -4,19 +4,13 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for the type converter. -/// +/// Tests for the type converter. public class DecimalToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,15 +20,13 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert DecimalToString Succeeds. - /// + /// Verifies TryConvert DecimalToString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_DecimalToString_Succeeds() { var converter = new DecimalToStringTypeConverter(); - const decimal value = 123.456m; + const decimal value = 123.456M; var result = converter.TryConvert(value, null, out var output); @@ -42,9 +34,7 @@ public async Task TryConvert_DecimalToString_Succeeds() await Assert.That(output).IsEqualTo("123.456"); } - /// - /// Verifies TryConvert MaxValue Succeeds. - /// + /// Verifies TryConvert MaxValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MaxValue_Succeeds() @@ -58,9 +48,7 @@ public async Task TryConvert_MaxValue_Succeeds() await Assert.That(output).IsEqualTo(decimal.MaxValue.ToString(System.Globalization.CultureInfo.CurrentCulture)); } - /// - /// Verifies TryConvert MinValue Succeeds. - /// + /// Verifies TryConvert MinValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MinValue_Succeeds() @@ -74,15 +62,13 @@ public async Task TryConvert_MinValue_Succeeds() await Assert.That(output).IsEqualTo(decimal.MinValue.ToString(System.Globalization.CultureInfo.CurrentCulture)); } - /// - /// Verifies TryConvert NegativeValue Succeeds. - /// + /// Verifies TryConvert NegativeValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NegativeValue_Succeeds() { var converter = new DecimalToStringTypeConverter(); - const decimal value = -123.456m; + const decimal value = -123.456M; var result = converter.TryConvert(value, null, out var output); @@ -90,31 +76,27 @@ public async Task TryConvert_NegativeValue_Succeeds() await Assert.That(output).IsEqualTo("-123.456"); } - /// - /// Verifies TryConvert WithConversionHint FormatsCorrectly. - /// + /// Verifies TryConvert WithConversionHint FormatsCorrectly. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithConversionHint_FormatsCorrectly() { var converter = new DecimalToStringTypeConverter(); - const decimal value = 42.5m; + const decimal value = 42.5M; - var result = converter.TryConvert(value, 2, out var output); + var result = converter.TryConvert(value, ExpectedAffinity, out var output); await Assert.That(result).IsTrue(); await Assert.That(output).IsEqualTo("42.50"); } - /// - /// Verifies TryConvert WithStringFormatHint CurrencyFormat. - /// + /// Verifies TryConvert WithStringFormatHint CurrencyFormat. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithStringFormatHint_CurrencyFormat() { var converter = new DecimalToStringTypeConverter(); - const decimal value = 1234.56m; + const decimal value = 1234.56M; var result = converter.TryConvert(value, "C", out var output); @@ -122,15 +104,13 @@ public async Task TryConvert_WithStringFormatHint_CurrencyFormat() await Assert.That(output).IsEqualTo(value.ToString("C")); } - /// - /// Verifies TryConvert WithStringFormatHint ExponentialFormat. - /// + /// Verifies TryConvert WithStringFormatHint ExponentialFormat. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithStringFormatHint_ExponentialFormat() { var converter = new DecimalToStringTypeConverter(); - const decimal value = 1234.5678m; + const decimal value = 1234.5678M; var result = converter.TryConvert(value, "E2", out var output); @@ -138,15 +118,13 @@ public async Task TryConvert_WithStringFormatHint_ExponentialFormat() await Assert.That(output).IsEqualTo(value.ToString("E2")); } - /// - /// Verifies TryConvert WithStringFormatHint FormatsCorrectly. - /// + /// Verifies TryConvert WithStringFormatHint FormatsCorrectly. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithStringFormatHint_FormatsCorrectly() { var converter = new DecimalToStringTypeConverter(); - const decimal value = 1234.5678m; + const decimal value = 1234.5678M; var result = converter.TryConvert(value, "N2", out var output); @@ -154,15 +132,13 @@ public async Task TryConvert_WithStringFormatHint_FormatsCorrectly() await Assert.That(output).IsEqualTo(value.ToString("N2")); } - /// - /// Verifies TryConvert WithStringFormatHint PercentFormat. - /// + /// Verifies TryConvert WithStringFormatHint PercentFormat. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithStringFormatHint_PercentFormat() { var converter = new DecimalToStringTypeConverter(); - const decimal value = 0.1234m; + const decimal value = 0.1234M; var result = converter.TryConvert(value, "P2", out var output); @@ -170,15 +146,13 @@ public async Task TryConvert_WithStringFormatHint_PercentFormat() await Assert.That(output).IsEqualTo(value.ToString("P2")); } - /// - /// Verifies TryConvert Zero Succeeds. - /// + /// Verifies TryConvert Zero Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Zero_Succeeds() { var converter = new DecimalToStringTypeConverter(); - const decimal value = 0m; + const decimal value = 0M; var result = converter.TryConvert(value, null, out var output); diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/DoubleToNullableDoubleTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/DoubleToNullableDoubleTypeConverterTests.cs index 5a0d12f..4000c25 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/DoubleToNullableDoubleTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/DoubleToNullableDoubleTypeConverterTests.cs @@ -4,24 +4,16 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting double to nullable double. -/// +/// Tests for converting double to nullable double. public class DoubleToNullableDoubleTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Sample double value used for precise conversion checks. - /// + /// Sample double value used for precise conversion checks. private const double SampleDouble = 123.456789; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -31,9 +23,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert AlwaysSucceeds. - /// + /// Verifies TryConvert AlwaysSucceeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_AlwaysSucceeds() @@ -47,9 +37,7 @@ public async Task TryConvert_AlwaysSucceeds() await Assert.That(output).IsEqualTo((double?)SampleDouble); } - /// - /// Verifies FromType ReturnsDouble. - /// + /// Verifies FromType ReturnsDouble. /// A task representing the asynchronous operation. [Test] public async Task FromType_ReturnsDouble() @@ -58,9 +46,7 @@ public async Task FromType_ReturnsDouble() await Assert.That(converter.FromType).IsEqualTo(typeof(double)); } - /// - /// Verifies ToType ReturnsDoubleNullable. - /// + /// Verifies ToType ReturnsDoubleNullable. /// A task representing the asynchronous operation. [Test] public async Task ToType_ReturnsDoubleNullable() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/DoubleToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/DoubleToStringTypeConverterTests.cs index 2d6973a..fc5982a 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/DoubleToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/DoubleToStringTypeConverterTests.cs @@ -4,19 +4,13 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for the type converter. -/// +/// Tests for the type converter. public class DoubleToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,9 +20,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert DoubleToString Succeeds. - /// + /// Verifies TryConvert DoubleToString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_DoubleToString_Succeeds() @@ -42,9 +34,7 @@ public async Task TryConvert_DoubleToString_Succeeds() await Assert.That(output).IsEqualTo(value.ToString(System.Globalization.CultureInfo.CurrentCulture)); } - /// - /// Verifies TryConvert MaxValue Succeeds. - /// + /// Verifies TryConvert MaxValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MaxValue_Succeeds() @@ -58,9 +48,7 @@ public async Task TryConvert_MaxValue_Succeeds() await Assert.That(output).IsEqualTo(double.MaxValue.ToString(System.Globalization.CultureInfo.CurrentCulture)); } - /// - /// Verifies TryConvert MinValue Succeeds. - /// + /// Verifies TryConvert MinValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MinValue_Succeeds() @@ -74,9 +62,7 @@ public async Task TryConvert_MinValue_Succeeds() await Assert.That(output).IsEqualTo(double.MinValue.ToString(System.Globalization.CultureInfo.CurrentCulture)); } - /// - /// Verifies TryConvert NegativeValue Succeeds. - /// + /// Verifies TryConvert NegativeValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NegativeValue_Succeeds() @@ -90,9 +76,7 @@ public async Task TryConvert_NegativeValue_Succeeds() await Assert.That(output).IsEqualTo(value.ToString(System.Globalization.CultureInfo.CurrentCulture)); } - /// - /// Verifies TryConvert WithConversionHint FormatsCorrectly. - /// + /// Verifies TryConvert WithConversionHint FormatsCorrectly. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithConversionHint_FormatsCorrectly() @@ -100,15 +84,13 @@ public async Task TryConvert_WithConversionHint_FormatsCorrectly() var converter = new DoubleToStringTypeConverter(); const double value = 42.5; - var result = converter.TryConvert(value, 2, out var output); + var result = converter.TryConvert(value, ExpectedAffinity, out var output); await Assert.That(result).IsTrue(); await Assert.That(output).IsEqualTo("42.50"); } - /// - /// Verifies TryConvert WithStringFormatHint CustomPrecision. - /// + /// Verifies TryConvert WithStringFormatHint CustomPrecision. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithStringFormatHint_CustomPrecision() @@ -122,9 +104,7 @@ public async Task TryConvert_WithStringFormatHint_CustomPrecision() await Assert.That(output).IsEqualTo(value.ToString("0.0000")); } - /// - /// Verifies TryConvert WithStringFormatHint GeneralFormat. - /// + /// Verifies TryConvert WithStringFormatHint GeneralFormat. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithStringFormatHint_GeneralFormat() @@ -138,9 +118,7 @@ public async Task TryConvert_WithStringFormatHint_GeneralFormat() await Assert.That(output).IsEqualTo(value.ToString("G")); } - /// - /// Verifies TryConvert WithStringFormatHint RoundTripFormat. - /// + /// Verifies TryConvert WithStringFormatHint RoundTripFormat. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithStringFormatHint_RoundTripFormat() @@ -154,9 +132,7 @@ public async Task TryConvert_WithStringFormatHint_RoundTripFormat() await Assert.That(output).IsEqualTo(value.ToString("R")); } - /// - /// Verifies TryConvert WithStringFormatHint ScientificFormat. - /// + /// Verifies TryConvert WithStringFormatHint ScientificFormat. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithStringFormatHint_ScientificFormat() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/EqualityTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/EqualityTypeConverterTests.cs index b49afe9..7d6611d 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/EqualityTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/EqualityTypeConverterTests.cs @@ -4,14 +4,16 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for the EqualityTypeConverter which compares objects for equality. -/// +/// Tests for the EqualityTypeConverter which compares objects for equality. public class EqualityTypeConverterTests { - /// - /// Verifies FromType ReturnsObjectType. - /// + /// A value deliberately different from SampleValue, so equality fails. + private const int DifferentValue = 43; + + /// A sample value used by these tests. + private const int SampleValue = 42; + + /// Verifies FromType ReturnsObjectType. /// A task representing the asynchronous operation. [Test] public async Task FromType_ReturnsObjectType() @@ -20,9 +22,7 @@ public async Task FromType_ReturnsObjectType() await Assert.That(converter.FromType).IsEqualTo(typeof(object)); } - /// - /// Verifies GetAffinityForObjects Returns1. - /// + /// Verifies GetAffinityForObjects Returns1. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns1() @@ -32,9 +32,7 @@ public async Task GetAffinityForObjects_Returns1() await Assert.That(affinity).IsEqualTo(1); } - /// - /// Verifies ToType ReturnsBoolType. - /// + /// Verifies ToType ReturnsBoolType. /// A task representing the asynchronous operation. [Test] public async Task ToType_ReturnsBoolType() @@ -43,9 +41,7 @@ public async Task ToType_ReturnsBoolType() await Assert.That(converter.ToType).IsEqualTo(typeof(bool)); } - /// - /// Verifies TryConvertTyped BothNull ReturnsTrue. - /// + /// Verifies TryConvertTyped BothNull ReturnsTrue. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_BothNull_ReturnsTrue() @@ -58,9 +54,7 @@ public async Task TryConvertTyped_BothNull_ReturnsTrue() await Assert.That((bool)output!).IsTrue(); } - /// - /// Verifies TryConvertTyped DifferentIntegers ReturnsFalse. - /// + /// Verifies TryConvertTyped DifferentIntegers ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_DifferentIntegers_ReturnsFalse() @@ -68,15 +62,13 @@ public async Task TryConvertTyped_DifferentIntegers_ReturnsFalse() var converter = new EqualityTypeConverter(); const int obj = 42; - var result = converter.TryConvertTyped(obj, 43, out var output); + var result = converter.TryConvertTyped(obj, DifferentValue, out var output); await Assert.That(result).IsTrue(); await Assert.That((bool)output!).IsFalse(); } - /// - /// Verifies TryConvertTyped DifferentTypes ReturnsFalse. - /// + /// Verifies TryConvertTyped DifferentTypes ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_DifferentTypes_ReturnsFalse() @@ -84,15 +76,13 @@ public async Task TryConvertTyped_DifferentTypes_ReturnsFalse() var converter = new EqualityTypeConverter(); const string obj = "42"; - var result = converter.TryConvertTyped(obj, 42, out var output); + var result = converter.TryConvertTyped(obj, SampleValue, out var output); await Assert.That(result).IsTrue(); await Assert.That((bool)output!).IsFalse(); } - /// - /// Verifies TryConvertTyped DifferentValues ReturnsFalse. - /// + /// Verifies TryConvertTyped DifferentValues ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_DifferentValues_ReturnsFalse() @@ -106,9 +96,7 @@ public async Task TryConvertTyped_DifferentValues_ReturnsFalse() await Assert.That((bool)output!).IsFalse(); } - /// - /// Verifies TryConvertTyped EqualIntegers ReturnsTrue. - /// + /// Verifies TryConvertTyped EqualIntegers ReturnsTrue. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_EqualIntegers_ReturnsTrue() @@ -116,15 +104,13 @@ public async Task TryConvertTyped_EqualIntegers_ReturnsTrue() var converter = new EqualityTypeConverter(); const int obj = 42; - var result = converter.TryConvertTyped(obj, 42, out var output); + var result = converter.TryConvertTyped(obj, SampleValue, out var output); await Assert.That(result).IsTrue(); await Assert.That((bool)output!).IsTrue(); } - /// - /// Verifies TryConvertTyped EqualStrings ReturnsTrue. - /// + /// Verifies TryConvertTyped EqualStrings ReturnsTrue. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_EqualStrings_ReturnsTrue() @@ -138,9 +124,7 @@ public async Task TryConvertTyped_EqualStrings_ReturnsTrue() await Assert.That((bool)output!).IsTrue(); } - /// - /// Verifies TryConvertTyped EqualValues ReturnsTrue. - /// + /// Verifies TryConvertTyped EqualValues ReturnsTrue. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_EqualValues_ReturnsTrue() @@ -154,9 +138,7 @@ public async Task TryConvertTyped_EqualValues_ReturnsTrue() await Assert.That((bool)output!).IsTrue(); } - /// - /// Verifies TryConvertTyped NoConversionHint UseNullComparison. - /// + /// Verifies TryConvertTyped NoConversionHint UseNullComparison. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_NoConversionHint_UseNullComparison() @@ -170,9 +152,7 @@ public async Task TryConvertTyped_NoConversionHint_UseNullComparison() await Assert.That((bool)output!).IsFalse(); } - /// - /// Verifies TryConvertTyped OneNull ReturnsFalse. - /// + /// Verifies TryConvertTyped OneNull ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_OneNull_ReturnsFalse() @@ -188,9 +168,7 @@ public async Task TryConvertTyped_OneNull_ReturnsFalse() await Assert.That((bool)output2!).IsFalse(); } - /// - /// Verifies TryConvertTyped ReferenceEquality ReturnsTrue. - /// + /// Verifies TryConvertTyped ReferenceEquality ReturnsTrue. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_ReferenceEquality_ReturnsTrue() @@ -204,9 +182,7 @@ public async Task TryConvertTyped_ReferenceEquality_ReturnsTrue() await Assert.That((bool)output!).IsTrue(); } - /// - /// Verifies TryConvertTyped ValueEquality ReturnsTrue. - /// + /// Verifies TryConvertTyped ValueEquality ReturnsTrue. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_ValueEquality_ReturnsTrue() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/GuidToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/GuidToStringTypeConverterTests.cs index 6b52535..78777f6 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/GuidToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/GuidToStringTypeConverterTests.cs @@ -4,19 +4,13 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting Guid to strings. -/// +/// Tests for converting Guid to strings. public class GuidToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,9 +20,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert Guid Succeeds. - /// + /// Verifies TryConvert Guid Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Guid_Succeeds() @@ -42,9 +34,7 @@ public async Task TryConvert_Guid_Succeeds() await Assert.That(output).IsEqualTo("12345678-1234-1234-1234-123456789abc"); } - /// - /// Verifies TryConvert EmptyGuid Succeeds. - /// + /// Verifies TryConvert EmptyGuid Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyGuid_Succeeds() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/IntegerToNullableIntegerTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/IntegerToNullableIntegerTypeConverterTests.cs index 3a2c7f7..52d5bf4 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/IntegerToNullableIntegerTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/IntegerToNullableIntegerTypeConverterTests.cs @@ -4,29 +4,19 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting int to nullable int. -/// +/// Tests for converting int to nullable int. public class IntegerToNullableIntegerTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Sample integer value used for conversion round-trips. - /// + /// Sample integer value used for conversion round-trips. private const int SampleInteger = 123_456; - /// - /// Smaller integer value used for conversion checks. - /// + /// Smaller integer value used for conversion checks. private const int SmallInteger = 42; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -36,9 +26,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert AlwaysSucceeds. - /// + /// Verifies TryConvert AlwaysSucceeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_AlwaysSucceeds() @@ -52,9 +40,7 @@ public async Task TryConvert_AlwaysSucceeds() await Assert.That(output).IsEqualTo((int?)SampleInteger); } - /// - /// Verifies FromType ReturnsInt. - /// + /// Verifies FromType ReturnsInt. /// A task representing the asynchronous operation. [Test] public async Task FromType_ReturnsInt() @@ -63,9 +49,7 @@ public async Task FromType_ReturnsInt() await Assert.That(converter.FromType).IsEqualTo(typeof(int)); } - /// - /// Verifies ToType ReturnsIntNullable. - /// + /// Verifies ToType ReturnsIntNullable. /// A task representing the asynchronous operation. [Test] public async Task ToType_ReturnsIntNullable() @@ -74,9 +58,7 @@ public async Task ToType_ReturnsIntNullable() await Assert.That(converter.ToType).IsEqualTo(typeof(int?)); } - /// - /// Verifies TryConvertTyped WithValidValue ReturnsTrueAndOutput. - /// + /// Verifies TryConvertTyped WithValidValue ReturnsTrueAndOutput. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithValidValue_ReturnsTrueAndOutput() @@ -90,9 +72,7 @@ public async Task TryConvertTyped_WithValidValue_ReturnsTrueAndOutput() await Assert.That(result).IsEqualTo((int?)SmallInteger); } - /// - /// Verifies TryConvertTyped WithNullValue ReturnsFalse. - /// + /// Verifies TryConvertTyped WithNullValue ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithNullValue_ReturnsFalse() @@ -105,9 +85,7 @@ public async Task TryConvertTyped_WithNullValue_ReturnsFalse() await Assert.That(result).IsNull(); } - /// - /// Verifies TryConvertTyped WithInvalidType ReturnsFalse. - /// + /// Verifies TryConvertTyped WithInvalidType ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithInvalidType_ReturnsFalse() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/IntegerToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/IntegerToStringTypeConverterTests.cs index d8cbbd6..08471be 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/IntegerToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/IntegerToStringTypeConverterTests.cs @@ -4,19 +4,16 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting integers to strings. -/// +/// Tests for converting integers to strings. public class IntegerToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// The conversion hint passed to the converter, which selects the output format. + private const int ConversionHint = 8; + + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,9 +23,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert IntToString Succeeds. - /// + /// Verifies TryConvert IntToString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_IntToString_Succeeds() @@ -42,9 +37,7 @@ public async Task TryConvert_IntToString_Succeeds() await Assert.That(output).IsEqualTo("123456"); } - /// - /// Verifies TryConvert MaxValue Succeeds. - /// + /// Verifies TryConvert MaxValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MaxValue_Succeeds() @@ -58,9 +51,7 @@ public async Task TryConvert_MaxValue_Succeeds() await Assert.That(output).IsEqualTo(int.MaxValue.ToString()); } - /// - /// Verifies TryConvert MinValue Succeeds. - /// + /// Verifies TryConvert MinValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MinValue_Succeeds() @@ -74,9 +65,7 @@ public async Task TryConvert_MinValue_Succeeds() await Assert.That(output).IsEqualTo(int.MinValue.ToString()); } - /// - /// Verifies TryConvert NegativeValue Succeeds. - /// + /// Verifies TryConvert NegativeValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NegativeValue_Succeeds() @@ -90,9 +79,7 @@ public async Task TryConvert_NegativeValue_Succeeds() await Assert.That(output).IsEqualTo("-123456"); } - /// - /// Verifies TryConvert WithConversionHint FormatsCorrectly. - /// + /// Verifies TryConvert WithConversionHint FormatsCorrectly. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithConversionHint_FormatsCorrectly() @@ -100,15 +87,13 @@ public async Task TryConvert_WithConversionHint_FormatsCorrectly() var converter = new IntegerToStringTypeConverter(); const int value = 42; - var result = converter.TryConvert(value, 8, out var output); + var result = converter.TryConvert(value, ConversionHint, out var output); await Assert.That(result).IsTrue(); await Assert.That(output).IsEqualTo("00000042"); } - /// - /// Verifies TryConvert WithStringFormatHint CustomFormat. - /// + /// Verifies TryConvert WithStringFormatHint CustomFormat. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithStringFormatHint_CustomFormat() @@ -122,9 +107,7 @@ public async Task TryConvert_WithStringFormatHint_CustomFormat() await Assert.That(output).IsEqualTo("042"); } - /// - /// Verifies TryConvert WithStringFormatHint HexFormat. - /// + /// Verifies TryConvert WithStringFormatHint HexFormat. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithStringFormatHint_HexFormat() @@ -138,9 +121,7 @@ public async Task TryConvert_WithStringFormatHint_HexFormat() await Assert.That(output).IsEqualTo("FF"); } - /// - /// Verifies TryConvert WithStringFormatHint HexFormatLowercase. - /// + /// Verifies TryConvert WithStringFormatHint HexFormatLowercase. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithStringFormatHint_HexFormatLowercase() @@ -154,9 +135,7 @@ public async Task TryConvert_WithStringFormatHint_HexFormatLowercase() await Assert.That(output).IsEqualTo("000000ff"); } - /// - /// Verifies TryConvert WithStringFormatHint NumberFormat. - /// + /// Verifies TryConvert WithStringFormatHint NumberFormat. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithStringFormatHint_NumberFormat() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/LongToNullableLongTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/LongToNullableLongTypeConverterTests.cs index d9e8b40..d487f88 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/LongToNullableLongTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/LongToNullableLongTypeConverterTests.cs @@ -4,29 +4,19 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting long to nullable long. -/// +/// Tests for converting long to nullable long. public class LongToNullableLongTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Sample long value used for conversion round-trips. - /// + /// Sample long value used for conversion round-trips. private const long SampleLong = 1_234_567_890_123_456L; - /// - /// Smaller long value used for conversion checks. - /// + /// Smaller long value used for conversion checks. private const long SmallLong = 42L; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -36,9 +26,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert AlwaysSucceeds. - /// + /// Verifies TryConvert AlwaysSucceeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_AlwaysSucceeds() @@ -52,9 +40,7 @@ public async Task TryConvert_AlwaysSucceeds() await Assert.That(output).IsEqualTo((long?)SampleLong); } - /// - /// Verifies FromType ReturnsLong. - /// + /// Verifies FromType ReturnsLong. /// A task representing the asynchronous operation. [Test] public async Task FromType_ReturnsLong() @@ -63,9 +49,7 @@ public async Task FromType_ReturnsLong() await Assert.That(converter.FromType).IsEqualTo(typeof(long)); } - /// - /// Verifies ToType ReturnsLongNullable. - /// + /// Verifies ToType ReturnsLongNullable. /// A task representing the asynchronous operation. [Test] public async Task ToType_ReturnsLongNullable() @@ -74,9 +58,7 @@ public async Task ToType_ReturnsLongNullable() await Assert.That(converter.ToType).IsEqualTo(typeof(long?)); } - /// - /// Verifies TryConvertTyped WithValidValue ReturnsTrueAndOutput. - /// + /// Verifies TryConvertTyped WithValidValue ReturnsTrueAndOutput. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithValidValue_ReturnsTrueAndOutput() @@ -90,9 +72,7 @@ public async Task TryConvertTyped_WithValidValue_ReturnsTrueAndOutput() await Assert.That(result).IsEqualTo((long?)SmallLong); } - /// - /// Verifies TryConvertTyped WithNullValue ReturnsFalse. - /// + /// Verifies TryConvertTyped WithNullValue ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithNullValue_ReturnsFalse() @@ -105,9 +85,7 @@ public async Task TryConvertTyped_WithNullValue_ReturnsFalse() await Assert.That(result).IsNull(); } - /// - /// Verifies TryConvertTyped WithInvalidType ReturnsFalse. - /// + /// Verifies TryConvertTyped WithInvalidType ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithInvalidType_ReturnsFalse() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/LongToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/LongToStringTypeConverterTests.cs index 766371d..7ae7b2d 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/LongToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/LongToStringTypeConverterTests.cs @@ -4,19 +4,16 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for the type converter. -/// +/// Tests for the type converter. public class LongToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// The conversion hint passed to the converter, which selects the output format. + private const int ConversionHint = 10; + + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,9 +23,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert LongToString Succeeds. - /// + /// Verifies TryConvert LongToString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_LongToString_Succeeds() @@ -42,9 +37,7 @@ public async Task TryConvert_LongToString_Succeeds() await Assert.That(output).IsEqualTo("123456789012"); } - /// - /// Verifies TryConvert MaxValue Succeeds. - /// + /// Verifies TryConvert MaxValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MaxValue_Succeeds() @@ -58,9 +51,7 @@ public async Task TryConvert_MaxValue_Succeeds() await Assert.That(output).IsEqualTo(long.MaxValue.ToString()); } - /// - /// Verifies TryConvert MinValue Succeeds. - /// + /// Verifies TryConvert MinValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MinValue_Succeeds() @@ -74,9 +65,7 @@ public async Task TryConvert_MinValue_Succeeds() await Assert.That(output).IsEqualTo(long.MinValue.ToString()); } - /// - /// Verifies TryConvert WithConversionHint FormatsCorrectly. - /// + /// Verifies TryConvert WithConversionHint FormatsCorrectly. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithConversionHint_FormatsCorrectly() @@ -84,15 +73,13 @@ public async Task TryConvert_WithConversionHint_FormatsCorrectly() var converter = new LongToStringTypeConverter(); const long value = 42; - var result = converter.TryConvert(value, 10, out var output); + var result = converter.TryConvert(value, ConversionHint, out var output); await Assert.That(result).IsTrue(); await Assert.That(output).IsEqualTo("0000000042"); } - /// - /// Verifies TryConvert with a string format hint formats correctly. - /// + /// Verifies TryConvert with a string format hint formats correctly. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithStringFormatHint_FormatsCorrectly() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableBooleanToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableBooleanToStringTypeConverterTests.cs index 048446d..f4d3e9f 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableBooleanToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableBooleanToStringTypeConverterTests.cs @@ -4,19 +4,13 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting nullable booleans to strings. -/// +/// Tests for converting nullable booleans to strings. public class NullableBooleanToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,9 +20,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert True ReturnsTrue. - /// + /// Verifies TryConvert True ReturnsTrue. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_True_ReturnsTrue() @@ -42,9 +34,7 @@ public async Task TryConvert_True_ReturnsTrue() await Assert.That(output).IsEqualTo("True"); } - /// - /// Verifies TryConvert False ReturnsFalse. - /// + /// Verifies TryConvert False ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_False_ReturnsFalse() @@ -58,9 +48,7 @@ public async Task TryConvert_False_ReturnsFalse() await Assert.That(output).IsEqualTo("False"); } - /// - /// Verifies TryConvert Null ReturnsNullString. - /// + /// Verifies TryConvert Null ReturnsNullString. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsNullString() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableByteToByteTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableByteToByteTypeConverterTests.cs index 090eaee..f264af9 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableByteToByteTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableByteToByteTypeConverterTests.cs @@ -4,24 +4,16 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting nullable byte to byte. -/// +/// Tests for converting nullable byte to byte. public class NullableByteToByteTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Sample byte value used for conversion round-trips. - /// + /// Sample byte value used for conversion round-trips. private const byte SampleByte = 42; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -31,9 +23,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert WithValue Succeeds. - /// + /// Verifies TryConvert WithValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithValue_Succeeds() @@ -44,12 +34,10 @@ public async Task TryConvert_WithValue_Succeeds() var result = converter.TryConvert(value, null, out var output); await Assert.That(result).IsTrue(); - await Assert.That(output).IsEqualTo((byte)SampleByte); + await Assert.That(output).IsEqualTo(SampleByte); } - /// - /// Verifies TryConvert Null ReturnsFalse. - /// + /// Verifies TryConvert Null ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsFalse() @@ -61,9 +49,7 @@ public async Task TryConvert_Null_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies FromType ReturnsByteNullable. - /// + /// Verifies FromType ReturnsByteNullable. /// A task representing the asynchronous operation. [Test] public async Task FromType_ReturnsByteNullable() @@ -72,9 +58,7 @@ public async Task FromType_ReturnsByteNullable() await Assert.That(converter.FromType).IsEqualTo(typeof(byte?)); } - /// - /// Verifies ToType ReturnsByte. - /// + /// Verifies ToType ReturnsByte. /// A task representing the asynchronous operation. [Test] public async Task ToType_ReturnsByte() @@ -83,9 +67,7 @@ public async Task ToType_ReturnsByte() await Assert.That(converter.ToType).IsEqualTo(typeof(byte)); } - /// - /// Verifies TryConvertTyped WithValidValue ReturnsTrueAndOutput. - /// + /// Verifies TryConvertTyped WithValidValue ReturnsTrueAndOutput. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithValidValue_ReturnsTrueAndOutput() @@ -96,12 +78,10 @@ public async Task TryConvertTyped_WithValidValue_ReturnsTrueAndOutput() var success = converter.TryConvertTyped(value, null, out var result); await Assert.That(success).IsTrue(); - await Assert.That(result).IsEqualTo((byte)SampleByte); + await Assert.That(result).IsEqualTo(SampleByte); } - /// - /// Verifies TryConvertTyped WithNullValue ReturnsFalse. - /// + /// Verifies TryConvertTyped WithNullValue ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithNullValue_ReturnsFalse() @@ -114,9 +94,7 @@ public async Task TryConvertTyped_WithNullValue_ReturnsFalse() await Assert.That(result).IsNull(); } - /// - /// Verifies TryConvertTyped WithInvalidType ReturnsFalse. - /// + /// Verifies TryConvertTyped WithInvalidType ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithInvalidType_ReturnsFalse() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableByteToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableByteToStringTypeConverterTests.cs index b6aed9c..9d98e0b 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableByteToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableByteToStringTypeConverterTests.cs @@ -4,19 +4,16 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for the type converter. -/// +/// Tests for the type converter. public class NullableByteToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// The conversion hint passed to the converter, which selects the output format. + private const int ConversionHint = 3; + + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,9 +23,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert ByteNullableToString Succeeds. - /// + /// Verifies TryConvert ByteNullableToString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_ByteNullableToString_Succeeds() @@ -42,9 +37,7 @@ public async Task TryConvert_ByteNullableToString_Succeeds() await Assert.That(output).IsEqualTo("123"); } - /// - /// Verifies TryConvert MaxValue Succeeds. - /// + /// Verifies TryConvert MaxValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MaxValue_Succeeds() @@ -58,9 +51,7 @@ public async Task TryConvert_MaxValue_Succeeds() await Assert.That(output).IsEqualTo("255"); } - /// - /// Verifies TryConvert MinValue Succeeds. - /// + /// Verifies TryConvert MinValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MinValue_Succeeds() @@ -74,9 +65,7 @@ public async Task TryConvert_MinValue_Succeeds() await Assert.That(output).IsEqualTo("0"); } - /// - /// Verifies TryConvert NullValue ReturnsTrue. - /// + /// Verifies TryConvert NullValue ReturnsTrue. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NullValue_ReturnsTrue() @@ -89,9 +78,7 @@ public async Task TryConvert_NullValue_ReturnsTrue() await Assert.That(output).IsNull(); } - /// - /// Verifies TryConvert WithConversionHint FormatsCorrectly. - /// + /// Verifies TryConvert WithConversionHint FormatsCorrectly. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithConversionHint_FormatsCorrectly() @@ -99,15 +86,13 @@ public async Task TryConvert_WithConversionHint_FormatsCorrectly() var converter = new NullableByteToStringTypeConverter(); byte? value = 5; - var result = converter.TryConvert(value, 3, out var output); + var result = converter.TryConvert(value, ConversionHint, out var output); await Assert.That(result).IsTrue(); await Assert.That(output).IsEqualTo("005"); } - /// - /// Verifies TryConvert with a string format hint formats correctly. - /// + /// Verifies TryConvert with a string format hint formats correctly. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithStringFormatHint_FormatsCorrectly() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableDateOnlyToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableDateOnlyToStringTypeConverterTests.cs index 313ec08..5e249e4 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableDateOnlyToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableDateOnlyToStringTypeConverterTests.cs @@ -5,19 +5,19 @@ #if NET6_0_OR_GREATER namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting nullable DateOnly to strings. -/// +/// Tests for converting nullable DateOnly to strings. public class NullableDateOnlyToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Year component of the sample date used across the conversion round-trips. + private const int SampleYear = 2_024; + + /// Day component of the sample date used across the conversion round-trips. + private const int SampleDay = 15; + + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -27,15 +27,13 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert DateOnly Succeeds. - /// + /// Verifies TryConvert DateOnly Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_DateOnly_Succeeds() { var converter = new NullableDateOnlyToStringTypeConverter(); - DateOnly? value = new DateOnly(2_024, 1, 15); + DateOnly? value = new DateOnly(SampleYear, 1, SampleDay); var result = converter.TryConvert(value, null, out var output); @@ -43,9 +41,7 @@ public async Task TryConvert_DateOnly_Succeeds() await Assert.That(output).IsEqualTo(value.Value.ToString()); } - /// - /// Verifies TryConvert Null ReturnsNullString. - /// + /// Verifies TryConvert Null ReturnsNullString. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsNullString() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableDateTimeOffsetToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableDateTimeOffsetToStringTypeConverterTests.cs index 9773872..70b3d27 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableDateTimeOffsetToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableDateTimeOffsetToStringTypeConverterTests.cs @@ -4,19 +4,16 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting nullable DateTimeOffset to strings. -/// +/// Tests for converting nullable DateTimeOffset to strings. public class NullableDateTimeOffsetToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// The UTC offset, in hours, of the sample timestamp under test. + private const int OffsetHours = -5; + + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,15 +23,13 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert DateTimeOffset Succeeds. - /// + /// Verifies TryConvert DateTimeOffset Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_DateTimeOffset_Succeeds() { var converter = new NullableDateTimeOffsetToStringTypeConverter(); - DateTimeOffset? value = new DateTimeOffset(2_024, 1, 15, 10, 30, 45, TimeSpan.FromHours(-5)); + DateTimeOffset? value = new DateTimeOffset(2_024, 1, 15, 10, 30, 45, TimeSpan.FromHours(OffsetHours)); var result = converter.TryConvert(value, null, out var output); @@ -42,9 +37,7 @@ public async Task TryConvert_DateTimeOffset_Succeeds() await Assert.That(output).IsEqualTo(value.Value.ToString()); } - /// - /// Verifies TryConvert Null ReturnsNullString. - /// + /// Verifies TryConvert Null ReturnsNullString. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsNullString() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableDateTimeToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableDateTimeToStringTypeConverterTests.cs index 5bb7d74..ead7dbf 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableDateTimeToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableDateTimeToStringTypeConverterTests.cs @@ -4,19 +4,13 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting nullable DateTime to strings. -/// +/// Tests for converting nullable DateTime to strings. public class NullableDateTimeToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,12 +20,9 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert DateTime Succeeds. - /// + /// Verifies TryConvert DateTime Succeeds. /// A task representing the asynchronous operation. [Test] - [SuppressMessage("Major Code Smell", "S6566:Use \"DateTimeOffset\" instead of \"DateTime\"", Justification = "Test data.")] public async Task TryConvert_DateTime_Succeeds() { var converter = new NullableDateTimeToStringTypeConverter(); @@ -43,9 +34,7 @@ public async Task TryConvert_DateTime_Succeeds() await Assert.That(output).IsEqualTo(value.Value.ToString(System.Globalization.CultureInfo.CurrentCulture)); } - /// - /// Verifies TryConvert Null ReturnsNullString. - /// + /// Verifies TryConvert Null ReturnsNullString. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsNullString() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableDecimalToDecimalTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableDecimalToDecimalTypeConverterTests.cs index 6ebb6ef..4f62359 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableDecimalToDecimalTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableDecimalToDecimalTypeConverterTests.cs @@ -4,29 +4,19 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting nullable decimal to decimal. -/// +/// Tests for converting nullable decimal to decimal. public class NullableDecimalToDecimalTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Sample decimal value used for precise conversion checks. - /// - private const decimal SampleDecimal = 123.456789m; + /// Sample decimal value used for precise conversion checks. + private const decimal SampleDecimal = 123.456789M; - /// - /// Sample rounded decimal value used for conversion checks. - /// - private const decimal RoundedDecimal = 42.5m; + /// Sample rounded decimal value used for conversion checks. + private const decimal RoundedDecimal = 42.5M; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -36,15 +26,13 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert WithValue Succeeds. - /// + /// Verifies TryConvert WithValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithValue_Succeeds() { var converter = new NullableDecimalToDecimalTypeConverter(); - decimal? value = 123.456789m; + decimal? value = 123.456789M; var result = converter.TryConvert(value, null, out var output); @@ -52,9 +40,7 @@ public async Task TryConvert_WithValue_Succeeds() await Assert.That(output).IsEqualTo(SampleDecimal); } - /// - /// Verifies TryConvert Null ReturnsFalse. - /// + /// Verifies TryConvert Null ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsFalse() @@ -66,9 +52,7 @@ public async Task TryConvert_Null_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies FromType ReturnsDecimalNullable. - /// + /// Verifies FromType ReturnsDecimalNullable. /// A task representing the asynchronous operation. [Test] public async Task FromType_ReturnsDecimalNullable() @@ -77,9 +61,7 @@ public async Task FromType_ReturnsDecimalNullable() await Assert.That(converter.FromType).IsEqualTo(typeof(decimal?)); } - /// - /// Verifies ToType ReturnsDecimal. - /// + /// Verifies ToType ReturnsDecimal. /// A task representing the asynchronous operation. [Test] public async Task ToType_ReturnsDecimal() @@ -88,15 +70,13 @@ public async Task ToType_ReturnsDecimal() await Assert.That(converter.ToType).IsEqualTo(typeof(decimal)); } - /// - /// Verifies TryConvertTyped WithValidValue ReturnsTrueAndOutput. - /// + /// Verifies TryConvertTyped WithValidValue ReturnsTrueAndOutput. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithValidValue_ReturnsTrueAndOutput() { var converter = new NullableDecimalToDecimalTypeConverter(); - decimal? value = 42.5m; + decimal? value = 42.5M; var success = converter.TryConvertTyped(value, null, out var result); @@ -104,9 +84,7 @@ public async Task TryConvertTyped_WithValidValue_ReturnsTrueAndOutput() await Assert.That(result).IsEqualTo(RoundedDecimal); } - /// - /// Verifies TryConvertTyped WithNullValue ReturnsFalse. - /// + /// Verifies TryConvertTyped WithNullValue ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithNullValue_ReturnsFalse() @@ -119,9 +97,7 @@ public async Task TryConvertTyped_WithNullValue_ReturnsFalse() await Assert.That(result).IsNull(); } - /// - /// Verifies TryConvertTyped WithInvalidType ReturnsFalse. - /// + /// Verifies TryConvertTyped WithInvalidType ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithInvalidType_ReturnsFalse() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableDecimalToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableDecimalToStringTypeConverterTests.cs index 3bfc56f..a2aa090 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableDecimalToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableDecimalToStringTypeConverterTests.cs @@ -4,19 +4,13 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for the type converter. -/// +/// Tests for the type converter. public class NullableDecimalToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,15 +20,13 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert DecimalNullableToString Succeeds. - /// + /// Verifies TryConvert DecimalNullableToString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_DecimalNullableToString_Succeeds() { var converter = new NullableDecimalToStringTypeConverter(); - decimal? value = 123.456m; + decimal? value = 123.456M; var result = converter.TryConvert(value, null, out var output); @@ -42,9 +34,7 @@ public async Task TryConvert_DecimalNullableToString_Succeeds() await Assert.That(output).IsEqualTo("123.456"); } - /// - /// Verifies TryConvert MaxValue Succeeds. - /// + /// Verifies TryConvert MaxValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MaxValue_Succeeds() @@ -58,9 +48,7 @@ public async Task TryConvert_MaxValue_Succeeds() await Assert.That(output).IsEqualTo(decimal.MaxValue.ToString(System.Globalization.CultureInfo.CurrentCulture)); } - /// - /// Verifies TryConvert MinValue Succeeds. - /// + /// Verifies TryConvert MinValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MinValue_Succeeds() @@ -74,15 +62,13 @@ public async Task TryConvert_MinValue_Succeeds() await Assert.That(output).IsEqualTo(decimal.MinValue.ToString(System.Globalization.CultureInfo.CurrentCulture)); } - /// - /// Verifies TryConvert NegativeValue Succeeds. - /// + /// Verifies TryConvert NegativeValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NegativeValue_Succeeds() { var converter = new NullableDecimalToStringTypeConverter(); - decimal? value = -123.456m; + decimal? value = -123.456M; var result = converter.TryConvert(value, null, out var output); @@ -90,9 +76,7 @@ public async Task TryConvert_NegativeValue_Succeeds() await Assert.That(output).IsEqualTo("-123.456"); } - /// - /// Verifies TryConvert NullValue ReturnsTrue. - /// + /// Verifies TryConvert NullValue ReturnsTrue. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NullValue_ReturnsTrue() @@ -103,31 +87,27 @@ public async Task TryConvert_NullValue_ReturnsTrue() await Assert.That(result).IsTrue(); } - /// - /// Verifies TryConvert WithConversionHint FormatsCorrectly. - /// + /// Verifies TryConvert WithConversionHint FormatsCorrectly. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithConversionHint_FormatsCorrectly() { var converter = new NullableDecimalToStringTypeConverter(); - decimal? value = 42.5m; + decimal? value = 42.5M; - var result = converter.TryConvert(value, 2, out var output); + var result = converter.TryConvert(value, ExpectedAffinity, out var output); await Assert.That(result).IsTrue(); await Assert.That(output).IsEqualTo("42.50"); } - /// - /// Verifies TryConvert Zero Succeeds. - /// + /// Verifies TryConvert Zero Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Zero_Succeeds() { var converter = new NullableDecimalToStringTypeConverter(); - decimal? value = 0m; + decimal? value = 0M; var result = converter.TryConvert(value, null, out var output); @@ -135,15 +115,13 @@ public async Task TryConvert_Zero_Succeeds() await Assert.That(output).IsEqualTo("0"); } - /// - /// Verifies TryConvert with a string format hint formats correctly. - /// + /// Verifies TryConvert with a string format hint formats correctly. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithStringFormatHint_FormatsCorrectly() { var converter = new NullableDecimalToStringTypeConverter(); - decimal? value = 42.5m; + decimal? value = 42.5M; var result = converter.TryConvert(value, "F4", out var output); diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableDoubleToDoubleTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableDoubleToDoubleTypeConverterTests.cs index 949b55f..fe0e1d7 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableDoubleToDoubleTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableDoubleToDoubleTypeConverterTests.cs @@ -4,24 +4,16 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting nullable double to double. -/// +/// Tests for converting nullable double to double. public class NullableDoubleToDoubleTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Sample double value used for precise conversion checks. - /// + /// Sample double value used for precise conversion checks. private const double SampleDouble = 123.456789; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -31,9 +23,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert WithValue Succeeds. - /// + /// Verifies TryConvert WithValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithValue_Succeeds() @@ -47,9 +37,7 @@ public async Task TryConvert_WithValue_Succeeds() await Assert.That(output).IsEqualTo(SampleDouble); } - /// - /// Verifies TryConvert Null ReturnsFalse. - /// + /// Verifies TryConvert Null ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsFalse() @@ -61,9 +49,7 @@ public async Task TryConvert_Null_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies FromType ReturnsDoubleNullable. - /// + /// Verifies FromType ReturnsDoubleNullable. /// A task representing the asynchronous operation. [Test] public async Task FromType_ReturnsDoubleNullable() @@ -72,9 +58,7 @@ public async Task FromType_ReturnsDoubleNullable() await Assert.That(converter.FromType).IsEqualTo(typeof(double?)); } - /// - /// Verifies ToType ReturnsDouble. - /// + /// Verifies ToType ReturnsDouble. /// A task representing the asynchronous operation. [Test] public async Task ToType_ReturnsDouble() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableDoubleToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableDoubleToStringTypeConverterTests.cs index a18fd76..23a6a24 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableDoubleToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableDoubleToStringTypeConverterTests.cs @@ -4,19 +4,13 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for the type converter. -/// +/// Tests for the type converter. public class NullableDoubleToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,9 +20,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert DoubleNullableToString Succeeds. - /// + /// Verifies TryConvert DoubleNullableToString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_DoubleNullableToString_Succeeds() @@ -42,9 +34,7 @@ public async Task TryConvert_DoubleNullableToString_Succeeds() await Assert.That(output).IsEqualTo(value.ToString()); } - /// - /// Verifies TryConvert MaxValue Succeeds. - /// + /// Verifies TryConvert MaxValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MaxValue_Succeeds() @@ -58,9 +48,7 @@ public async Task TryConvert_MaxValue_Succeeds() await Assert.That(output).IsEqualTo(double.MaxValue.ToString(System.Globalization.CultureInfo.CurrentCulture)); } - /// - /// Verifies TryConvert MinValue Succeeds. - /// + /// Verifies TryConvert MinValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MinValue_Succeeds() @@ -74,9 +62,7 @@ public async Task TryConvert_MinValue_Succeeds() await Assert.That(output).IsEqualTo(double.MinValue.ToString(System.Globalization.CultureInfo.CurrentCulture)); } - /// - /// Verifies TryConvert NegativeValue Succeeds. - /// + /// Verifies TryConvert NegativeValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NegativeValue_Succeeds() @@ -90,9 +76,7 @@ public async Task TryConvert_NegativeValue_Succeeds() await Assert.That(output).IsEqualTo(value.ToString()); } - /// - /// Verifies TryConvert NullValue ReturnsTrue. - /// + /// Verifies TryConvert NullValue ReturnsTrue. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NullValue_ReturnsTrue() @@ -103,9 +87,7 @@ public async Task TryConvert_NullValue_ReturnsTrue() await Assert.That(result).IsTrue(); } - /// - /// Verifies TryConvert WithConversionHint FormatsCorrectly. - /// + /// Verifies TryConvert WithConversionHint FormatsCorrectly. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithConversionHint_FormatsCorrectly() @@ -113,15 +95,13 @@ public async Task TryConvert_WithConversionHint_FormatsCorrectly() var converter = new NullableDoubleToStringTypeConverter(); double? value = 42.5; - var result = converter.TryConvert(value, 2, out var output); + var result = converter.TryConvert(value, ExpectedAffinity, out var output); await Assert.That(result).IsTrue(); await Assert.That(output).IsEqualTo("42.50"); } - /// - /// Verifies TryConvert with a string format hint formats correctly. - /// + /// Verifies TryConvert with a string format hint formats correctly. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithStringFormatHint_FormatsCorrectly() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableGuidToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableGuidToStringTypeConverterTests.cs index 7fa00aa..3955cce 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableGuidToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableGuidToStringTypeConverterTests.cs @@ -4,19 +4,13 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting nullable Guid to strings. -/// +/// Tests for converting nullable Guid to strings. public class NullableGuidToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,9 +20,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert Guid Succeeds. - /// + /// Verifies TryConvert Guid Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Guid_Succeeds() @@ -42,9 +34,7 @@ public async Task TryConvert_Guid_Succeeds() await Assert.That(output).IsEqualTo("12345678-1234-1234-1234-123456789abc"); } - /// - /// Verifies TryConvert Null ReturnsNullString. - /// + /// Verifies TryConvert Null ReturnsNullString. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsNullString() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableIntegerToIntegerTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableIntegerToIntegerTypeConverterTests.cs index 7b0a404..9844fa6 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableIntegerToIntegerTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableIntegerToIntegerTypeConverterTests.cs @@ -4,29 +4,19 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting nullable int to int. -/// +/// Tests for converting nullable int to int. public class NullableIntegerToIntegerTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Sample integer value used for conversion round-trips. - /// + /// Sample integer value used for conversion round-trips. private const int SampleInteger = 123_456; - /// - /// Smaller integer value used for conversion checks. - /// + /// Smaller integer value used for conversion checks. private const int SmallInteger = 42; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -36,9 +26,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert WithValue Succeeds. - /// + /// Verifies TryConvert WithValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithValue_Succeeds() @@ -52,9 +40,7 @@ public async Task TryConvert_WithValue_Succeeds() await Assert.That(output).IsEqualTo(SampleInteger); } - /// - /// Verifies TryConvert Null ReturnsFalse. - /// + /// Verifies TryConvert Null ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsFalse() @@ -66,9 +52,7 @@ public async Task TryConvert_Null_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies FromType ReturnsIntNullable. - /// + /// Verifies FromType ReturnsIntNullable. /// A task representing the asynchronous operation. [Test] public async Task FromType_ReturnsIntNullable() @@ -77,9 +61,7 @@ public async Task FromType_ReturnsIntNullable() await Assert.That(converter.FromType).IsEqualTo(typeof(int?)); } - /// - /// Verifies ToType ReturnsInt. - /// + /// Verifies ToType ReturnsInt. /// A task representing the asynchronous operation. [Test] public async Task ToType_ReturnsInt() @@ -88,9 +70,7 @@ public async Task ToType_ReturnsInt() await Assert.That(converter.ToType).IsEqualTo(typeof(int)); } - /// - /// Verifies TryConvertTyped WithValidValue ReturnsTrueAndOutput. - /// + /// Verifies TryConvertTyped WithValidValue ReturnsTrueAndOutput. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithValidValue_ReturnsTrueAndOutput() @@ -104,9 +84,7 @@ public async Task TryConvertTyped_WithValidValue_ReturnsTrueAndOutput() await Assert.That(result).IsEqualTo(SmallInteger); } - /// - /// Verifies TryConvertTyped WithNullValue ReturnsFalse. - /// + /// Verifies TryConvertTyped WithNullValue ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithNullValue_ReturnsFalse() @@ -119,9 +97,7 @@ public async Task TryConvertTyped_WithNullValue_ReturnsFalse() await Assert.That(result).IsNull(); } - /// - /// Verifies TryConvertTyped WithInvalidType ReturnsFalse. - /// + /// Verifies TryConvertTyped WithInvalidType ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithInvalidType_ReturnsFalse() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableIntegerToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableIntegerToStringTypeConverterTests.cs index a04dfd6..ff24c1d 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableIntegerToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableIntegerToStringTypeConverterTests.cs @@ -4,19 +4,16 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for the type converter. -/// +/// Tests for the type converter. public class NullableIntegerToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// The conversion hint passed to the converter, which selects the output format. + private const int ConversionHint = 8; + + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,9 +23,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert IntNullableToString Succeeds. - /// + /// Verifies TryConvert IntNullableToString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_IntNullableToString_Succeeds() @@ -42,9 +37,7 @@ public async Task TryConvert_IntNullableToString_Succeeds() await Assert.That(output).IsEqualTo("123456"); } - /// - /// Verifies TryConvert MaxValue Succeeds. - /// + /// Verifies TryConvert MaxValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MaxValue_Succeeds() @@ -58,9 +51,7 @@ public async Task TryConvert_MaxValue_Succeeds() await Assert.That(output).IsEqualTo(int.MaxValue.ToString()); } - /// - /// Verifies TryConvert MinValue Succeeds. - /// + /// Verifies TryConvert MinValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MinValue_Succeeds() @@ -74,9 +65,7 @@ public async Task TryConvert_MinValue_Succeeds() await Assert.That(output).IsEqualTo(int.MinValue.ToString()); } - /// - /// Verifies TryConvert NullValue ReturnsTrue. - /// + /// Verifies TryConvert NullValue ReturnsTrue. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NullValue_ReturnsTrue() @@ -87,9 +76,7 @@ public async Task TryConvert_NullValue_ReturnsTrue() await Assert.That(result).IsTrue(); } - /// - /// Verifies TryConvert WithConversionHint FormatsCorrectly. - /// + /// Verifies TryConvert WithConversionHint FormatsCorrectly. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithConversionHint_FormatsCorrectly() @@ -97,15 +84,13 @@ public async Task TryConvert_WithConversionHint_FormatsCorrectly() var converter = new NullableIntegerToStringTypeConverter(); int? value = 42; - var result = converter.TryConvert(value, 8, out var output); + var result = converter.TryConvert(value, ConversionHint, out var output); await Assert.That(result).IsTrue(); await Assert.That(output).IsEqualTo("00000042"); } - /// - /// Verifies TryConvert with a string format hint formats correctly. - /// + /// Verifies TryConvert with a string format hint formats correctly. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithStringFormatHint_FormatsCorrectly() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableLongToLongTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableLongToLongTypeConverterTests.cs index 4fd8370..525b5a3 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableLongToLongTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableLongToLongTypeConverterTests.cs @@ -4,29 +4,19 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting nullable long to long. -/// +/// Tests for converting nullable long to long. public class NullableLongToLongTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Sample long value used for conversion round-trips. - /// + /// Sample long value used for conversion round-trips. private const long SampleLong = 1_234_567_890_123_456L; - /// - /// Smaller long value used for conversion checks. - /// + /// Smaller long value used for conversion checks. private const long SmallLong = 42L; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -36,9 +26,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert WithValue Succeeds. - /// + /// Verifies TryConvert WithValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithValue_Succeeds() @@ -52,9 +40,7 @@ public async Task TryConvert_WithValue_Succeeds() await Assert.That(output).IsEqualTo(SampleLong); } - /// - /// Verifies TryConvert Null ReturnsFalse. - /// + /// Verifies TryConvert Null ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsFalse() @@ -66,9 +52,7 @@ public async Task TryConvert_Null_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies FromType ReturnsLongNullable. - /// + /// Verifies FromType ReturnsLongNullable. /// A task representing the asynchronous operation. [Test] public async Task FromType_ReturnsLongNullable() @@ -77,9 +61,7 @@ public async Task FromType_ReturnsLongNullable() await Assert.That(converter.FromType).IsEqualTo(typeof(long?)); } - /// - /// Verifies ToType ReturnsLong. - /// + /// Verifies ToType ReturnsLong. /// A task representing the asynchronous operation. [Test] public async Task ToType_ReturnsLong() @@ -88,9 +70,7 @@ public async Task ToType_ReturnsLong() await Assert.That(converter.ToType).IsEqualTo(typeof(long)); } - /// - /// Verifies TryConvertTyped WithValidValue ReturnsTrueAndOutput. - /// + /// Verifies TryConvertTyped WithValidValue ReturnsTrueAndOutput. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithValidValue_ReturnsTrueAndOutput() @@ -104,9 +84,7 @@ public async Task TryConvertTyped_WithValidValue_ReturnsTrueAndOutput() await Assert.That(result).IsEqualTo(SmallLong); } - /// - /// Verifies TryConvertTyped WithNullValue ReturnsFalse. - /// + /// Verifies TryConvertTyped WithNullValue ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithNullValue_ReturnsFalse() @@ -119,9 +97,7 @@ public async Task TryConvertTyped_WithNullValue_ReturnsFalse() await Assert.That(result).IsNull(); } - /// - /// Verifies TryConvertTyped WithInvalidType ReturnsFalse. - /// + /// Verifies TryConvertTyped WithInvalidType ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithInvalidType_ReturnsFalse() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableLongToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableLongToStringTypeConverterTests.cs index 8283c77..d128fbb 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableLongToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableLongToStringTypeConverterTests.cs @@ -4,19 +4,16 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for the type converter. -/// +/// Tests for the type converter. public class NullableLongToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// The conversion hint passed to the converter, which selects the output format. + private const int ConversionHint = 10; + + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,9 +23,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert LongNullableToString Succeeds. - /// + /// Verifies TryConvert LongNullableToString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_LongNullableToString_Succeeds() @@ -42,9 +37,7 @@ public async Task TryConvert_LongNullableToString_Succeeds() await Assert.That(output).IsEqualTo("123456789012"); } - /// - /// Verifies TryConvert MaxValue Succeeds. - /// + /// Verifies TryConvert MaxValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MaxValue_Succeeds() @@ -58,9 +51,7 @@ public async Task TryConvert_MaxValue_Succeeds() await Assert.That(output).IsEqualTo(long.MaxValue.ToString()); } - /// - /// Verifies TryConvert MinValue Succeeds. - /// + /// Verifies TryConvert MinValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MinValue_Succeeds() @@ -74,9 +65,7 @@ public async Task TryConvert_MinValue_Succeeds() await Assert.That(output).IsEqualTo(long.MinValue.ToString()); } - /// - /// Verifies TryConvert NullValue ReturnsTrue. - /// + /// Verifies TryConvert NullValue ReturnsTrue. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NullValue_ReturnsTrue() @@ -87,9 +76,7 @@ public async Task TryConvert_NullValue_ReturnsTrue() await Assert.That(result).IsTrue(); } - /// - /// Verifies TryConvert WithConversionHint FormatsCorrectly. - /// + /// Verifies TryConvert WithConversionHint FormatsCorrectly. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithConversionHint_FormatsCorrectly() @@ -97,15 +84,13 @@ public async Task TryConvert_WithConversionHint_FormatsCorrectly() var converter = new NullableLongToStringTypeConverter(); long? value = 42; - var result = converter.TryConvert(value, 10, out var output); + var result = converter.TryConvert(value, ConversionHint, out var output); await Assert.That(result).IsTrue(); await Assert.That(output).IsEqualTo("0000000042"); } - /// - /// Verifies TryConvert with a string format hint formats correctly. - /// + /// Verifies TryConvert with a string format hint formats correctly. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithStringFormatHint_FormatsCorrectly() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableShortToShortTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableShortToShortTypeConverterTests.cs index 80deeb1..d0f458f 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableShortToShortTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableShortToShortTypeConverterTests.cs @@ -4,29 +4,19 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting nullable short to short. -/// +/// Tests for converting nullable short to short. public class NullableShortToShortTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Sample short value used for conversion round-trips. - /// + /// Sample short value used for conversion round-trips. private const short SampleShort = 1_234; - /// - /// Smaller short value used for conversion checks. - /// + /// Smaller short value used for conversion checks. private const short SmallShort = 42; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -36,9 +26,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert WithValue Succeeds. - /// + /// Verifies TryConvert WithValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithValue_Succeeds() @@ -49,12 +37,10 @@ public async Task TryConvert_WithValue_Succeeds() var result = converter.TryConvert(value, null, out var output); await Assert.That(result).IsTrue(); - await Assert.That(output).IsEqualTo((short)SampleShort); + await Assert.That(output).IsEqualTo(SampleShort); } - /// - /// Verifies TryConvert Null ReturnsFalse. - /// + /// Verifies TryConvert Null ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsFalse() @@ -66,9 +52,7 @@ public async Task TryConvert_Null_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies FromType ReturnsShortNullable. - /// + /// Verifies FromType ReturnsShortNullable. /// A task representing the asynchronous operation. [Test] public async Task FromType_ReturnsShortNullable() @@ -77,9 +61,7 @@ public async Task FromType_ReturnsShortNullable() await Assert.That(converter.FromType).IsEqualTo(typeof(short?)); } - /// - /// Verifies ToType ReturnsShort. - /// + /// Verifies ToType ReturnsShort. /// A task representing the asynchronous operation. [Test] public async Task ToType_ReturnsShort() @@ -88,9 +70,7 @@ public async Task ToType_ReturnsShort() await Assert.That(converter.ToType).IsEqualTo(typeof(short)); } - /// - /// Verifies TryConvertTyped WithValidValue ReturnsTrueAndOutput. - /// + /// Verifies TryConvertTyped WithValidValue ReturnsTrueAndOutput. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithValidValue_ReturnsTrueAndOutput() @@ -101,12 +81,10 @@ public async Task TryConvertTyped_WithValidValue_ReturnsTrueAndOutput() var success = converter.TryConvertTyped(value, null, out var result); await Assert.That(success).IsTrue(); - await Assert.That(result).IsEqualTo((short)SmallShort); + await Assert.That(result).IsEqualTo(SmallShort); } - /// - /// Verifies TryConvertTyped WithNullValue ReturnsFalse. - /// + /// Verifies TryConvertTyped WithNullValue ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithNullValue_ReturnsFalse() @@ -119,9 +97,7 @@ public async Task TryConvertTyped_WithNullValue_ReturnsFalse() await Assert.That(result).IsNull(); } - /// - /// Verifies TryConvertTyped WithInvalidType ReturnsFalse. - /// + /// Verifies TryConvertTyped WithInvalidType ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithInvalidType_ReturnsFalse() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableShortToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableShortToStringTypeConverterTests.cs index f374441..a8ffc81 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableShortToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableShortToStringTypeConverterTests.cs @@ -4,19 +4,16 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for the type converter. -/// +/// Tests for the type converter. public class NullableShortToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// The conversion hint passed to the converter, which selects the output format. + private const int ConversionHint = 5; + + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,9 +23,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert MaxValue Succeeds. - /// + /// Verifies TryConvert MaxValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MaxValue_Succeeds() @@ -42,9 +37,7 @@ public async Task TryConvert_MaxValue_Succeeds() await Assert.That(output).IsEqualTo(short.MaxValue.ToString()); } - /// - /// Verifies TryConvert MinValue Succeeds. - /// + /// Verifies TryConvert MinValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MinValue_Succeeds() @@ -58,9 +51,7 @@ public async Task TryConvert_MinValue_Succeeds() await Assert.That(output).IsEqualTo(short.MinValue.ToString()); } - /// - /// Verifies TryConvert NullValue ReturnsTrue. - /// + /// Verifies TryConvert NullValue ReturnsTrue. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NullValue_ReturnsTrue() @@ -71,9 +62,7 @@ public async Task TryConvert_NullValue_ReturnsTrue() await Assert.That(result).IsTrue(); } - /// - /// Verifies TryConvert ShortNullableToString Succeeds. - /// + /// Verifies TryConvert ShortNullableToString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_ShortNullableToString_Succeeds() @@ -87,9 +76,7 @@ public async Task TryConvert_ShortNullableToString_Succeeds() await Assert.That(output).IsEqualTo("12345"); } - /// - /// Verifies TryConvert WithConversionHint FormatsCorrectly. - /// + /// Verifies TryConvert WithConversionHint FormatsCorrectly. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithConversionHint_FormatsCorrectly() @@ -97,15 +84,13 @@ public async Task TryConvert_WithConversionHint_FormatsCorrectly() var converter = new NullableShortToStringTypeConverter(); short? value = 42; - var result = converter.TryConvert(value, 5, out var output); + var result = converter.TryConvert(value, ConversionHint, out var output); await Assert.That(result).IsTrue(); await Assert.That(output).IsEqualTo("00042"); } - /// - /// Verifies TryConvert with a string format hint formats correctly. - /// + /// Verifies TryConvert with a string format hint formats correctly. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithStringFormatHint_FormatsCorrectly() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableSingleToSingleTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableSingleToSingleTypeConverterTests.cs index 2fefeaf..e4673ea 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableSingleToSingleTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableSingleToSingleTypeConverterTests.cs @@ -4,29 +4,19 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting nullable float to float. -/// +/// Tests for converting nullable float to float. public class NullableSingleToSingleTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Sample single-precision value used for conversion checks. - /// - private const float SampleSingle = 123.45f; + /// Sample single-precision value used for conversion checks. + private const float SampleSingle = 123.45F; - /// - /// Sample rounded single-precision value used for conversion checks. - /// - private const float RoundedSingle = 42.5f; + /// Sample rounded single-precision value used for conversion checks. + private const float RoundedSingle = 42.5F; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -36,15 +26,13 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert WithValue Succeeds. - /// + /// Verifies TryConvert WithValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithValue_Succeeds() { var converter = new NullableSingleToSingleTypeConverter(); - float? value = 123.45f; + float? value = 123.45F; var result = converter.TryConvert(value, null, out var output); @@ -52,9 +40,7 @@ public async Task TryConvert_WithValue_Succeeds() await Assert.That(output).IsEqualTo(SampleSingle); } - /// - /// Verifies TryConvert Null ReturnsFalse. - /// + /// Verifies TryConvert Null ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsFalse() @@ -66,9 +52,7 @@ public async Task TryConvert_Null_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies FromType ReturnsFloatNullable. - /// + /// Verifies FromType ReturnsFloatNullable. /// A task representing the asynchronous operation. [Test] public async Task FromType_ReturnsFloatNullable() @@ -77,9 +61,7 @@ public async Task FromType_ReturnsFloatNullable() await Assert.That(converter.FromType).IsEqualTo(typeof(float?)); } - /// - /// Verifies ToType ReturnsSingle. - /// + /// Verifies ToType ReturnsSingle. /// A task representing the asynchronous operation. [Test] public async Task ToType_ReturnsSingle() @@ -88,15 +70,13 @@ public async Task ToType_ReturnsSingle() await Assert.That(converter.ToType).IsEqualTo(typeof(float)); } - /// - /// Verifies TryConvertTyped WithValidValue ReturnsTrueAndOutput. - /// + /// Verifies TryConvertTyped WithValidValue ReturnsTrueAndOutput. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithValidValue_ReturnsTrueAndOutput() { var converter = new NullableSingleToSingleTypeConverter(); - float? value = 42.5f; + float? value = 42.5F; var success = converter.TryConvertTyped(value, null, out var result); @@ -104,9 +84,7 @@ public async Task TryConvertTyped_WithValidValue_ReturnsTrueAndOutput() await Assert.That(result).IsEqualTo(RoundedSingle); } - /// - /// Verifies TryConvertTyped WithNullValue ReturnsFalse. - /// + /// Verifies TryConvertTyped WithNullValue ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithNullValue_ReturnsFalse() @@ -119,9 +97,7 @@ public async Task TryConvertTyped_WithNullValue_ReturnsFalse() await Assert.That(result).IsNull(); } - /// - /// Verifies TryConvertTyped WithInvalidType ReturnsFalse. - /// + /// Verifies TryConvertTyped WithInvalidType ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithInvalidType_ReturnsFalse() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableSingleToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableSingleToStringTypeConverterTests.cs index c70f1d0..810ac5f 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableSingleToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableSingleToStringTypeConverterTests.cs @@ -4,19 +4,13 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for the type converter. -/// +/// Tests for the type converter. public class NullableSingleToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,9 +20,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert MaxValue Succeeds. - /// + /// Verifies TryConvert MaxValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MaxValue_Succeeds() @@ -42,9 +34,7 @@ public async Task TryConvert_MaxValue_Succeeds() await Assert.That(output).IsEqualTo(float.MaxValue.ToString(System.Globalization.CultureInfo.CurrentCulture)); } - /// - /// Verifies TryConvert MinValue Succeeds. - /// + /// Verifies TryConvert MinValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MinValue_Succeeds() @@ -58,15 +48,13 @@ public async Task TryConvert_MinValue_Succeeds() await Assert.That(output).IsEqualTo(float.MinValue.ToString(System.Globalization.CultureInfo.CurrentCulture)); } - /// - /// Verifies TryConvert NegativeValue Succeeds. - /// + /// Verifies TryConvert NegativeValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NegativeValue_Succeeds() { var converter = new NullableSingleToStringTypeConverter(); - float? value = -123.456f; + float? value = -123.456F; var result = converter.TryConvert(value, null, out var output); @@ -74,9 +62,7 @@ public async Task TryConvert_NegativeValue_Succeeds() await Assert.That(output).IsEqualTo(value.ToString()); } - /// - /// Verifies TryConvert NullValue ReturnsTrue. - /// + /// Verifies TryConvert NullValue ReturnsTrue. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NullValue_ReturnsTrue() @@ -87,15 +73,13 @@ public async Task TryConvert_NullValue_ReturnsTrue() await Assert.That(result).IsTrue(); } - /// - /// Verifies TryConvert SingleNullableToString Succeeds. - /// + /// Verifies TryConvert SingleNullableToString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_SingleNullableToString_Succeeds() { var converter = new NullableSingleToStringTypeConverter(); - float? value = 123.456f; + float? value = 123.456F; var result = converter.TryConvert(value, null, out var output); @@ -103,31 +87,27 @@ public async Task TryConvert_SingleNullableToString_Succeeds() await Assert.That(output).IsEqualTo(value.ToString()); } - /// - /// Verifies TryConvert WithConversionHint FormatsCorrectly. - /// + /// Verifies TryConvert WithConversionHint FormatsCorrectly. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithConversionHint_FormatsCorrectly() { var converter = new NullableSingleToStringTypeConverter(); - float? value = 42.5f; + float? value = 42.5F; - var result = converter.TryConvert(value, 2, out var output); + var result = converter.TryConvert(value, ExpectedAffinity, out var output); await Assert.That(result).IsTrue(); await Assert.That(output).IsEqualTo("42.50"); } - /// - /// Verifies TryConvert with a string format hint formats correctly. - /// + /// Verifies TryConvert with a string format hint formats correctly. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithStringFormatHint_FormatsCorrectly() { var converter = new NullableSingleToStringTypeConverter(); - float? value = 42.5f; + float? value = 42.5F; var result = converter.TryConvert(value, "E2", out var output); diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableTimeOnlyToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableTimeOnlyToStringTypeConverterTests.cs index 79468b9..4517e5e 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableTimeOnlyToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableTimeOnlyToStringTypeConverterTests.cs @@ -5,19 +5,22 @@ #if NET6_0_OR_GREATER namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting nullable TimeOnly to strings. -/// +/// Tests for converting nullable TimeOnly to strings. public class NullableTimeOnlyToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Hour component of the sample time used across the conversion round-trips. + private const int SampleHour = 10; + + /// Minute component of the sample time used across the conversion round-trips. + private const int SampleMinute = 30; + + /// Second component of the sample time used across the conversion round-trips. + private const int SampleSecond = 45; + + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -27,15 +30,13 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert TimeOnly Succeeds. - /// + /// Verifies TryConvert TimeOnly Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_TimeOnly_Succeeds() { var converter = new NullableTimeOnlyToStringTypeConverter(); - TimeOnly? value = new TimeOnly(10, 30, 45); + TimeOnly? value = new TimeOnly(SampleHour, SampleMinute, SampleSecond); var result = converter.TryConvert(value, null, out var output); @@ -43,9 +44,7 @@ public async Task TryConvert_TimeOnly_Succeeds() await Assert.That(output).IsEqualTo(value.Value.ToString()); } - /// - /// Verifies TryConvert Null ReturnsNullString. - /// + /// Verifies TryConvert Null ReturnsNullString. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsNullString() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableTimeSpanToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableTimeSpanToStringTypeConverterTests.cs index c25eaae..669ef44 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableTimeSpanToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/NullableTimeSpanToStringTypeConverterTests.cs @@ -4,19 +4,16 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting nullable TimeSpan to strings. -/// +/// Tests for converting nullable TimeSpan to strings. public class NullableTimeSpanToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// The number of hours in the sample duration under test. + private const double SampleHours = 2.5; + + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,15 +23,13 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert TimeSpan Succeeds. - /// + /// Verifies TryConvert TimeSpan Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_TimeSpan_Succeeds() { var converter = new NullableTimeSpanToStringTypeConverter(); - TimeSpan? value = TimeSpan.FromHours(2.5); + TimeSpan? value = TimeSpan.FromHours(SampleHours); var result = converter.TryConvert(value, null, out var output); @@ -42,9 +37,7 @@ public async Task TryConvert_TimeSpan_Succeeds() await Assert.That(output).IsEqualTo(value.Value.ToString()); } - /// - /// Verifies TryConvert Null ReturnsNullString. - /// + /// Verifies TryConvert Null ReturnsNullString. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsNullString() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/ShortToNullableShortTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/ShortToNullableShortTypeConverterTests.cs index 6269c52..d22e253 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/ShortToNullableShortTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/ShortToNullableShortTypeConverterTests.cs @@ -4,29 +4,19 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting short to nullable short. -/// +/// Tests for converting short to nullable short. public class ShortToNullableShortTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Sample short value used for conversion round-trips. - /// + /// Sample short value used for conversion round-trips. private const short SampleShort = 1_234; - /// - /// Smaller short value used for conversion checks. - /// + /// Smaller short value used for conversion checks. private const short SmallShort = 42; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -36,9 +26,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert AlwaysSucceeds. - /// + /// Verifies TryConvert AlwaysSucceeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_AlwaysSucceeds() @@ -52,9 +40,7 @@ public async Task TryConvert_AlwaysSucceeds() await Assert.That(output).IsEqualTo((short?)SampleShort); } - /// - /// Verifies FromType ReturnsShort. - /// + /// Verifies FromType ReturnsShort. /// A task representing the asynchronous operation. [Test] public async Task FromType_ReturnsShort() @@ -63,9 +49,7 @@ public async Task FromType_ReturnsShort() await Assert.That(converter.FromType).IsEqualTo(typeof(short)); } - /// - /// Verifies ToType ReturnsShortNullable. - /// + /// Verifies ToType ReturnsShortNullable. /// A task representing the asynchronous operation. [Test] public async Task ToType_ReturnsShortNullable() @@ -74,9 +58,7 @@ public async Task ToType_ReturnsShortNullable() await Assert.That(converter.ToType).IsEqualTo(typeof(short?)); } - /// - /// Verifies TryConvertTyped WithValidValue ReturnsTrueAndOutput. - /// + /// Verifies TryConvertTyped WithValidValue ReturnsTrueAndOutput. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithValidValue_ReturnsTrueAndOutput() @@ -90,9 +72,7 @@ public async Task TryConvertTyped_WithValidValue_ReturnsTrueAndOutput() await Assert.That(result).IsEqualTo((short?)SmallShort); } - /// - /// Verifies TryConvertTyped WithNullValue ReturnsFalse. - /// + /// Verifies TryConvertTyped WithNullValue ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithNullValue_ReturnsFalse() @@ -105,9 +85,7 @@ public async Task TryConvertTyped_WithNullValue_ReturnsFalse() await Assert.That(result).IsNull(); } - /// - /// Verifies TryConvertTyped WithInvalidType ReturnsFalse. - /// + /// Verifies TryConvertTyped WithInvalidType ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithInvalidType_ReturnsFalse() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/ShortToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/ShortToStringTypeConverterTests.cs index 4c45a35..0d4ec9a 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/ShortToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/ShortToStringTypeConverterTests.cs @@ -4,19 +4,16 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for the type converter. -/// +/// Tests for the type converter. public class ShortToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// The conversion hint passed to the converter, which selects the output format. + private const int ConversionHint = 5; + + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,9 +23,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert MaxValue Succeeds. - /// + /// Verifies TryConvert MaxValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MaxValue_Succeeds() @@ -42,9 +37,7 @@ public async Task TryConvert_MaxValue_Succeeds() await Assert.That(output).IsEqualTo(short.MaxValue.ToString()); } - /// - /// Verifies TryConvert MinValue Succeeds. - /// + /// Verifies TryConvert MinValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MinValue_Succeeds() @@ -58,9 +51,7 @@ public async Task TryConvert_MinValue_Succeeds() await Assert.That(output).IsEqualTo(short.MinValue.ToString()); } - /// - /// Verifies TryConvert ShortToString Succeeds. - /// + /// Verifies TryConvert ShortToString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_ShortToString_Succeeds() @@ -74,9 +65,7 @@ public async Task TryConvert_ShortToString_Succeeds() await Assert.That(output).IsEqualTo("12345"); } - /// - /// Verifies TryConvert WithConversionHint FormatsCorrectly. - /// + /// Verifies TryConvert WithConversionHint FormatsCorrectly. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithConversionHint_FormatsCorrectly() @@ -84,15 +73,13 @@ public async Task TryConvert_WithConversionHint_FormatsCorrectly() var converter = new ShortToStringTypeConverter(); const short value = 42; - var result = converter.TryConvert(value, 5, out var output); + var result = converter.TryConvert(value, ConversionHint, out var output); await Assert.That(result).IsTrue(); await Assert.That(output).IsEqualTo("00042"); } - /// - /// Verifies TryConvert with a string format hint formats correctly. - /// + /// Verifies TryConvert with a string format hint formats correctly. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithStringFormatHint_FormatsCorrectly() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/SingleToNullableSingleTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/SingleToNullableSingleTypeConverterTests.cs index bc08295..b40d9cb 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/SingleToNullableSingleTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/SingleToNullableSingleTypeConverterTests.cs @@ -4,29 +4,19 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting float to nullable float. -/// +/// Tests for converting float to nullable float. public class SingleToNullableSingleTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Sample single-precision value used for conversion checks. - /// - private const float SampleSingle = 123.45f; + /// Sample single-precision value used for conversion checks. + private const float SampleSingle = 123.45F; - /// - /// Sample rounded single-precision value used for conversion checks. - /// - private const float RoundedSingle = 42.5f; + /// Sample rounded single-precision value used for conversion checks. + private const float RoundedSingle = 42.5F; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -36,15 +26,13 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert AlwaysSucceeds. - /// + /// Verifies TryConvert AlwaysSucceeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_AlwaysSucceeds() { var converter = new SingleToNullableSingleTypeConverter(); - const float value = 123.45f; + const float value = 123.45F; var result = converter.TryConvert(value, null, out var output); @@ -52,9 +40,7 @@ public async Task TryConvert_AlwaysSucceeds() await Assert.That(output).IsEqualTo((float?)SampleSingle); } - /// - /// Verifies FromType ReturnsFloat. - /// + /// Verifies FromType ReturnsFloat. /// A task representing the asynchronous operation. [Test] public async Task FromType_ReturnsFloat() @@ -63,9 +49,7 @@ public async Task FromType_ReturnsFloat() await Assert.That(converter.FromType).IsEqualTo(typeof(float)); } - /// - /// Verifies ToType ReturnsSingleNullable. - /// + /// Verifies ToType ReturnsSingleNullable. /// A task representing the asynchronous operation. [Test] public async Task ToType_ReturnsSingleNullable() @@ -74,15 +58,13 @@ public async Task ToType_ReturnsSingleNullable() await Assert.That(converter.ToType).IsEqualTo(typeof(float?)); } - /// - /// Verifies TryConvertTyped WithValidValue ReturnsTrueAndOutput. - /// + /// Verifies TryConvertTyped WithValidValue ReturnsTrueAndOutput. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithValidValue_ReturnsTrueAndOutput() { var converter = new SingleToNullableSingleTypeConverter(); - const float value = 42.5f; + const float value = 42.5F; var success = converter.TryConvertTyped(value, null, out var result); @@ -90,9 +72,7 @@ public async Task TryConvertTyped_WithValidValue_ReturnsTrueAndOutput() await Assert.That(result).IsEqualTo((float?)RoundedSingle); } - /// - /// Verifies TryConvertTyped WithNullValue ReturnsFalse. - /// + /// Verifies TryConvertTyped WithNullValue ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithNullValue_ReturnsFalse() @@ -105,9 +85,7 @@ public async Task TryConvertTyped_WithNullValue_ReturnsFalse() await Assert.That(result).IsNull(); } - /// - /// Verifies TryConvertTyped WithInvalidType ReturnsFalse. - /// + /// Verifies TryConvertTyped WithInvalidType ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_WithInvalidType_ReturnsFalse() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/SingleToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/SingleToStringTypeConverterTests.cs index dfee436..808527b 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/SingleToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/SingleToStringTypeConverterTests.cs @@ -4,19 +4,13 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for the type converter. -/// +/// Tests for the type converter. public class SingleToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,9 +20,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert MaxValue Succeeds. - /// + /// Verifies TryConvert MaxValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MaxValue_Succeeds() @@ -42,9 +34,7 @@ public async Task TryConvert_MaxValue_Succeeds() await Assert.That(output).IsEqualTo(float.MaxValue.ToString(System.Globalization.CultureInfo.CurrentCulture)); } - /// - /// Verifies TryConvert MinValue Succeeds. - /// + /// Verifies TryConvert MinValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MinValue_Succeeds() @@ -58,15 +48,13 @@ public async Task TryConvert_MinValue_Succeeds() await Assert.That(output).IsEqualTo(float.MinValue.ToString(System.Globalization.CultureInfo.CurrentCulture)); } - /// - /// Verifies TryConvert NegativeValue Succeeds. - /// + /// Verifies TryConvert NegativeValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NegativeValue_Succeeds() { var converter = new SingleToStringTypeConverter(); - const float value = -123.456f; + const float value = -123.456F; var result = converter.TryConvert(value, null, out var output); @@ -74,15 +62,13 @@ public async Task TryConvert_NegativeValue_Succeeds() await Assert.That(output).IsEqualTo(value.ToString(System.Globalization.CultureInfo.CurrentCulture)); } - /// - /// Verifies TryConvert SingleToString Succeeds. - /// + /// Verifies TryConvert SingleToString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_SingleToString_Succeeds() { var converter = new SingleToStringTypeConverter(); - const float value = 123.456f; + const float value = 123.456F; var result = converter.TryConvert(value, null, out var output); @@ -90,31 +76,27 @@ public async Task TryConvert_SingleToString_Succeeds() await Assert.That(output).IsEqualTo(value.ToString(System.Globalization.CultureInfo.CurrentCulture)); } - /// - /// Verifies TryConvert WithConversionHint FormatsCorrectly. - /// + /// Verifies TryConvert WithConversionHint FormatsCorrectly. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithConversionHint_FormatsCorrectly() { var converter = new SingleToStringTypeConverter(); - const float value = 42.5f; + const float value = 42.5F; - var result = converter.TryConvert(value, 2, out var output); + var result = converter.TryConvert(value, ExpectedAffinity, out var output); await Assert.That(result).IsTrue(); await Assert.That(output).IsEqualTo("42.50"); } - /// - /// Verifies TryConvert with a string format hint formats correctly. - /// + /// Verifies TryConvert with a string format hint formats correctly. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_WithStringFormatHint_FormatsCorrectly() { var converter = new SingleToStringTypeConverter(); - const float value = 42.5f; + const float value = 42.5F; var result = converter.TryConvert(value, "E2", out var output); diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringConverterTests.cs index 4110537..d594f86 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringConverterTests.cs @@ -4,19 +4,13 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for the type converter. -/// +/// Tests for the type converter. public class StringConverterTests { - /// - /// The expected affinity reported by the string converter. - /// + /// The expected affinity reported by the string converter. private const int ExpectedAffinity = 2; - /// - /// Verifies FromType ReturnsStringType. - /// + /// Verifies FromType ReturnsStringType. /// A task representing the asynchronous operation. [Test] public async Task FromType_ReturnsStringType() @@ -25,9 +19,7 @@ public async Task FromType_ReturnsStringType() await Assert.That(converter.FromType).IsEqualTo(typeof(string)); } - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -37,9 +29,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies ToType ReturnsStringType. - /// + /// Verifies ToType ReturnsStringType. /// A task representing the asynchronous operation. [Test] public async Task ToType_ReturnsStringType() @@ -48,9 +38,7 @@ public async Task ToType_ReturnsStringType() await Assert.That(converter.ToType).IsEqualTo(typeof(string)); } - /// - /// Verifies TryConvertTyped EmptyString Succeeds. - /// + /// Verifies TryConvertTyped EmptyString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_EmptyString_Succeeds() @@ -64,9 +52,7 @@ public async Task TryConvertTyped_EmptyString_Succeeds() await Assert.That(output).IsEqualTo(string.Empty); } - /// - /// Verifies TryConvertTyped IgnoresConversionHint. - /// + /// Verifies TryConvertTyped IgnoresConversionHint. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_IgnoresConversionHint() @@ -80,9 +66,7 @@ public async Task TryConvertTyped_IgnoresConversionHint() await Assert.That(output).IsEqualTo("test"); } - /// - /// Verifies TryConvertTyped NonStringValue ReturnsFalse. - /// + /// Verifies TryConvertTyped NonStringValue ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_NonStringValue_ReturnsFalse() @@ -94,9 +78,7 @@ public async Task TryConvertTyped_NonStringValue_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvertTyped NullValue ReturnsFalseAndNull. - /// + /// Verifies TryConvertTyped NullValue ReturnsFalseAndNull. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_NullValue_ReturnsFalseAndNull() @@ -109,9 +91,7 @@ public async Task TryConvertTyped_NullValue_ReturnsFalseAndNull() await Assert.That(output).IsNull(); } - /// - /// Verifies TryConvertTyped StringToString Succeeds. - /// + /// Verifies TryConvertTyped StringToString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_StringToString_Succeeds() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToBooleanTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToBooleanTypeConverterTests.cs index 09950a9..1a44871 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToBooleanTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToBooleanTypeConverterTests.cs @@ -4,19 +4,13 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to booleans. -/// +/// Tests for converting strings to booleans. public class StringToBooleanTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,9 +20,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert TrueString Succeeds. - /// + /// Verifies TryConvert TrueString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_TrueString_Succeeds() @@ -41,9 +33,7 @@ public async Task TryConvert_TrueString_Succeeds() await Assert.That(output).IsTrue(); } - /// - /// Verifies TryConvert FalseString Succeeds. - /// + /// Verifies TryConvert FalseString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_FalseString_Succeeds() @@ -56,9 +46,7 @@ public async Task TryConvert_FalseString_Succeeds() await Assert.That(output).IsFalse(); } - /// - /// Verifies TryConvert TrueLowercase Succeeds. - /// + /// Verifies TryConvert TrueLowercase Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_TrueLowercase_Succeeds() @@ -71,9 +59,7 @@ public async Task TryConvert_TrueLowercase_Succeeds() await Assert.That(output).IsTrue(); } - /// - /// Verifies TryConvert FalseLowercase Succeeds. - /// + /// Verifies TryConvert FalseLowercase Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_FalseLowercase_Succeeds() @@ -86,9 +72,7 @@ public async Task TryConvert_FalseLowercase_Succeeds() await Assert.That(output).IsFalse(); } - /// - /// Verifies TryConvert Null ReturnsFalse. - /// + /// Verifies TryConvert Null ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsFalse() @@ -99,9 +83,7 @@ public async Task TryConvert_Null_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert EmptyString ReturnsFalse. - /// + /// Verifies TryConvert EmptyString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_ReturnsFalse() @@ -112,9 +94,7 @@ public async Task TryConvert_EmptyString_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert InvalidString ReturnsFalse. - /// + /// Verifies TryConvert InvalidString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_InvalidString_ReturnsFalse() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToByteTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToByteTypeConverterTests.cs index 04b90cd..637eba2 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToByteTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToByteTypeConverterTests.cs @@ -4,34 +4,22 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to bytes. -/// +/// Tests for converting strings to bytes. public class StringToByteTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Byte value parsed from a typical numeric string. - /// + /// Byte value parsed from a typical numeric string. private const byte ParsedByte = 123; - /// - /// Byte maximum value parsed from string. - /// + /// Byte maximum value parsed from string. private const byte MaxByte = 255; - /// - /// Byte value parsed in the typed conversion test. - /// + /// Byte value parsed in the typed conversion test. private const byte TypedByte = 100; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -41,9 +29,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert EmptyString ReturnsFalse. - /// + /// Verifies TryConvert EmptyString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_ReturnsFalse() @@ -54,9 +40,7 @@ public async Task TryConvert_EmptyString_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert InvalidString ReturnsFalse. - /// + /// Verifies TryConvert InvalidString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_InvalidString_ReturnsFalse() @@ -67,9 +51,7 @@ public async Task TryConvert_InvalidString_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert NegativeValue ReturnsFalse. - /// + /// Verifies TryConvert NegativeValue ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NegativeValue_ReturnsFalse() @@ -80,9 +62,7 @@ public async Task TryConvert_NegativeValue_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert OutOfRangeValue ReturnsFalse. - /// + /// Verifies TryConvert OutOfRangeValue ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_OutOfRangeValue_ReturnsFalse() @@ -93,9 +73,7 @@ public async Task TryConvert_OutOfRangeValue_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert StringToByte Succeeds. - /// + /// Verifies TryConvert StringToByte Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_StringToByte_Succeeds() @@ -105,12 +83,10 @@ public async Task TryConvert_StringToByte_Succeeds() var result = converter.TryConvert("123", null, out var output); await Assert.That(result).IsTrue(); - await Assert.That(output).IsEqualTo((byte)ParsedByte); + await Assert.That(output).IsEqualTo(ParsedByte); } - /// - /// Verifies TryConvert NullString ReturnsFalse. - /// + /// Verifies TryConvert NullString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NullString_ReturnsFalse() @@ -123,9 +99,7 @@ public async Task TryConvert_NullString_ReturnsFalse() await Assert.That(output).IsEqualTo((byte)0); } - /// - /// Verifies TryConvert ZeroValue Succeeds. - /// + /// Verifies TryConvert ZeroValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_ZeroValue_Succeeds() @@ -138,9 +112,7 @@ public async Task TryConvert_ZeroValue_Succeeds() await Assert.That(output).IsEqualTo((byte)0); } - /// - /// Verifies TryConvert MaxValue Succeeds. - /// + /// Verifies TryConvert MaxValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MaxValue_Succeeds() @@ -150,12 +122,10 @@ public async Task TryConvert_MaxValue_Succeeds() var result = converter.TryConvert("255", null, out var output); await Assert.That(result).IsTrue(); - await Assert.That(output).IsEqualTo((byte)MaxByte); + await Assert.That(output).IsEqualTo(MaxByte); } - /// - /// Verifies TryConvertTyped ValidString Succeeds. - /// + /// Verifies TryConvertTyped ValidString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_ValidString_Succeeds() @@ -165,27 +135,23 @@ public async Task TryConvertTyped_ValidString_Succeeds() var result = converter.TryConvertTyped("100", null, out var output); await Assert.That(result).IsTrue(); - await Assert.That(output).IsEqualTo((byte)TypedByte); + await Assert.That(output).IsEqualTo(TypedByte); } - /// - /// Verifies TryConvertTyped InvalidType ReturnsFalse. - /// + /// Verifies TryConvertTyped InvalidType ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_InvalidType_ReturnsFalse() { var converter = new StringToByteTypeConverter(); - var result = converter.TryConvertTyped(123, null, out var output); + var result = converter.TryConvertTyped(ParsedByte, null, out var output); await Assert.That(result).IsFalse(); await Assert.That(output).IsNull(); } - /// - /// Verifies TryConvertTyped NullInput ReturnsFalse. - /// + /// Verifies TryConvertTyped NullInput ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_NullInput_ReturnsFalse() @@ -198,9 +164,7 @@ public async Task TryConvertTyped_NullInput_ReturnsFalse() await Assert.That(output).IsNull(); } - /// - /// Verifies FromType ReturnsStringType. - /// + /// Verifies FromType ReturnsStringType. /// A task representing the asynchronous operation. [Test] public async Task FromType_ReturnsStringType() @@ -210,9 +174,7 @@ public async Task FromType_ReturnsStringType() await Assert.That(converter.FromType).IsEqualTo(typeof(string)); } - /// - /// Verifies ToType ReturnsByteType. - /// + /// Verifies ToType ReturnsByteType. /// A task representing the asynchronous operation. [Test] public async Task ToType_ReturnsByteType() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToDateOnlyTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToDateOnlyTypeConverterTests.cs index 6208c5b..a9815e7 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToDateOnlyTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToDateOnlyTypeConverterTests.cs @@ -5,19 +5,19 @@ #if NET6_0_OR_GREATER namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to DateOnly. -/// +/// Tests for converting strings to DateOnly. public class StringToDateOnlyTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Year component of the sample date used across the conversion round-trips. + private const int SampleYear = 2_024; + + /// Day component of the sample date used across the conversion round-trips. + private const int SampleDay = 15; + + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -27,15 +27,13 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert ValidString Succeeds. - /// + /// Verifies TryConvert ValidString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_ValidString_Succeeds() { var converter = new StringToDateOnlyTypeConverter(); - var expected = new DateOnly(2_024, 1, 15); + var expected = new DateOnly(SampleYear, 1, SampleDay); var result = converter.TryConvert(expected.ToString(), null, out var output); @@ -43,9 +41,7 @@ public async Task TryConvert_ValidString_Succeeds() await Assert.That(output).IsEqualTo(expected); } - /// - /// Verifies TryConvert Null ReturnsFalse. - /// + /// Verifies TryConvert Null ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsFalse() @@ -56,9 +52,7 @@ public async Task TryConvert_Null_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert EmptyString ReturnsFalse. - /// + /// Verifies TryConvert EmptyString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_ReturnsFalse() @@ -69,9 +63,7 @@ public async Task TryConvert_EmptyString_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert InvalidString ReturnsFalse. - /// + /// Verifies TryConvert InvalidString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_InvalidString_ReturnsFalse() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToDateTimeOffsetTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToDateTimeOffsetTypeConverterTests.cs index 125d6d1..9eaacb0 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToDateTimeOffsetTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToDateTimeOffsetTypeConverterTests.cs @@ -4,19 +4,13 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to DateTimeOffset. -/// +/// Tests for converting strings to DateTimeOffset. public class StringToDateTimeOffsetTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,9 +20,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert ValidString Succeeds. - /// + /// Verifies TryConvert ValidString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_ValidString_Succeeds() @@ -42,9 +34,7 @@ public async Task TryConvert_ValidString_Succeeds() await Assert.That(output).IsEqualTo(expected); } - /// - /// Verifies TryConvert Null ReturnsFalse. - /// + /// Verifies TryConvert Null ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsFalse() @@ -55,9 +45,7 @@ public async Task TryConvert_Null_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert EmptyString ReturnsFalse. - /// + /// Verifies TryConvert EmptyString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_ReturnsFalse() @@ -68,9 +56,7 @@ public async Task TryConvert_EmptyString_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert InvalidString ReturnsFalse. - /// + /// Verifies TryConvert InvalidString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_InvalidString_ReturnsFalse() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToDateTimeTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToDateTimeTypeConverterTests.cs index e393f11..8cfcc6a 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToDateTimeTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToDateTimeTypeConverterTests.cs @@ -4,19 +4,13 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to DateTime. -/// +/// Tests for converting strings to DateTime. public class StringToDateTimeTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,12 +20,9 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert ValidString Succeeds. - /// + /// Verifies TryConvert ValidString Succeeds. /// A task representing the asynchronous operation. [Test] - [SuppressMessage("Major Code Smell", "S6566:Use \"DateTimeOffset\" instead of \"DateTime\"", Justification = "Test data.")] public async Task TryConvert_ValidString_Succeeds() { var converter = new StringToDateTimeTypeConverter(); @@ -43,9 +34,7 @@ public async Task TryConvert_ValidString_Succeeds() await Assert.That(output).IsEqualTo(expected); } - /// - /// Verifies TryConvert Null ReturnsFalse. - /// + /// Verifies TryConvert Null ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsFalse() @@ -56,9 +45,7 @@ public async Task TryConvert_Null_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert EmptyString ReturnsFalse. - /// + /// Verifies TryConvert EmptyString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_ReturnsFalse() @@ -69,9 +56,7 @@ public async Task TryConvert_EmptyString_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert InvalidString ReturnsFalse. - /// + /// Verifies TryConvert InvalidString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_InvalidString_ReturnsFalse() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToDecimalTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToDecimalTypeConverterTests.cs index 4f472c6..2ed3d93 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToDecimalTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToDecimalTypeConverterTests.cs @@ -4,34 +4,22 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to decimals. -/// +/// Tests for converting strings to decimals. public class StringToDecimalTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Decimal value parsed from a positive numeric string. - /// - private const decimal ParsedDecimal = 123.456m; + /// Decimal value parsed from a positive numeric string. + private const decimal ParsedDecimal = 123.456M; - /// - /// Decimal value parsed from a negative numeric string. - /// - private const decimal NegativeDecimal = -123.456m; + /// Decimal value parsed from a negative numeric string. + private const decimal NegativeDecimal = -123.456M; - /// - /// Decimal value parsed in the typed conversion test. - /// - private const decimal TypedDecimal = 456.789m; + /// Decimal value parsed in the typed conversion test. + private const decimal TypedDecimal = 456.789M; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -41,9 +29,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert EmptyString ReturnsFalse. - /// + /// Verifies TryConvert EmptyString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_ReturnsFalse() @@ -54,9 +40,7 @@ public async Task TryConvert_EmptyString_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert InvalidString ReturnsFalse. - /// + /// Verifies TryConvert InvalidString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_InvalidString_ReturnsFalse() @@ -67,9 +51,7 @@ public async Task TryConvert_InvalidString_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert StringToDecimal Succeeds. - /// + /// Verifies TryConvert StringToDecimal Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_StringToDecimal_Succeeds() @@ -82,9 +64,7 @@ public async Task TryConvert_StringToDecimal_Succeeds() await Assert.That(output).IsEqualTo(ParsedDecimal); } - /// - /// Verifies TryConvert NullString ReturnsFalse. - /// + /// Verifies TryConvert NullString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NullString_ReturnsFalse() @@ -94,12 +74,10 @@ public async Task TryConvert_NullString_ReturnsFalse() var result = converter.TryConvert(null, null, out var output); await Assert.That(result).IsFalse(); - await Assert.That(output).IsEqualTo(0m); + await Assert.That(output).IsEqualTo(0M); } - /// - /// Verifies TryConvert ZeroValue Succeeds. - /// + /// Verifies TryConvert ZeroValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_ZeroValue_Succeeds() @@ -109,12 +87,10 @@ public async Task TryConvert_ZeroValue_Succeeds() var result = converter.TryConvert("0", null, out var output); await Assert.That(result).IsTrue(); - await Assert.That(output).IsEqualTo(0m); + await Assert.That(output).IsEqualTo(0M); } - /// - /// Verifies TryConvert NegativeValue Succeeds. - /// + /// Verifies TryConvert NegativeValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NegativeValue_Succeeds() @@ -127,9 +103,7 @@ public async Task TryConvert_NegativeValue_Succeeds() await Assert.That(output).IsEqualTo(NegativeDecimal); } - /// - /// Verifies TryConvertTyped ValidString Succeeds. - /// + /// Verifies TryConvertTyped ValidString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_ValidString_Succeeds() @@ -142,24 +116,20 @@ public async Task TryConvertTyped_ValidString_Succeeds() await Assert.That(output).IsEqualTo(TypedDecimal); } - /// - /// Verifies TryConvertTyped InvalidType ReturnsFalse. - /// + /// Verifies TryConvertTyped InvalidType ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_InvalidType_ReturnsFalse() { var converter = new StringToDecimalTypeConverter(); - var result = converter.TryConvertTyped(123.456, null, out var output); + var result = converter.TryConvertTyped(ParsedDecimal, null, out var output); await Assert.That(result).IsFalse(); await Assert.That(output).IsNull(); } - /// - /// Verifies TryConvertTyped NullInput ReturnsFalse. - /// + /// Verifies TryConvertTyped NullInput ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_NullInput_ReturnsFalse() @@ -172,9 +142,7 @@ public async Task TryConvertTyped_NullInput_ReturnsFalse() await Assert.That(output).IsNull(); } - /// - /// Verifies FromType ReturnsStringType. - /// + /// Verifies FromType ReturnsStringType. /// A task representing the asynchronous operation. [Test] public async Task FromType_ReturnsStringType() @@ -184,9 +152,7 @@ public async Task FromType_ReturnsStringType() await Assert.That(converter.FromType).IsEqualTo(typeof(string)); } - /// - /// Verifies ToType ReturnsDecimalType. - /// + /// Verifies ToType ReturnsDecimalType. /// A task representing the asynchronous operation. [Test] public async Task ToType_ReturnsDecimalType() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToDoubleTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToDoubleTypeConverterTests.cs index 19681a6..ba1e547 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToDoubleTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToDoubleTypeConverterTests.cs @@ -4,39 +4,25 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to doubles. -/// +/// Tests for converting strings to doubles. public class StringToDoubleTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Double value parsed from scientific notation. - /// + /// Double value parsed from scientific notation. private const double ScientificDouble = 1.23E+10; - /// - /// Double value parsed from a positive numeric string. - /// + /// Double value parsed from a positive numeric string. private const double ParsedDouble = 123.456; - /// - /// Double value parsed from a negative numeric string. - /// + /// Double value parsed from a negative numeric string. private const double NegativeDouble = -123.456; - /// - /// Double value parsed in the typed conversion test. - /// + /// Double value parsed in the typed conversion test. private const double TypedDouble = 456.789; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -46,9 +32,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert EmptyString ReturnsFalse. - /// + /// Verifies TryConvert EmptyString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_ReturnsFalse() @@ -59,9 +43,7 @@ public async Task TryConvert_EmptyString_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert InvalidString ReturnsFalse. - /// + /// Verifies TryConvert InvalidString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_InvalidString_ReturnsFalse() @@ -72,9 +54,7 @@ public async Task TryConvert_InvalidString_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert ScientificNotation Succeeds. - /// + /// Verifies TryConvert ScientificNotation Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_ScientificNotation_Succeeds() @@ -87,9 +67,7 @@ public async Task TryConvert_ScientificNotation_Succeeds() await Assert.That(output).IsEqualTo(ScientificDouble); } - /// - /// Verifies TryConvert StringToDouble Succeeds. - /// + /// Verifies TryConvert StringToDouble Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_StringToDouble_Succeeds() @@ -102,9 +80,7 @@ public async Task TryConvert_StringToDouble_Succeeds() await Assert.That(output).IsEqualTo(ParsedDouble); } - /// - /// Verifies TryConvert NullString ReturnsFalse. - /// + /// Verifies TryConvert NullString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NullString_ReturnsFalse() @@ -117,9 +93,7 @@ public async Task TryConvert_NullString_ReturnsFalse() await Assert.That(output).IsEqualTo(0.0); } - /// - /// Verifies TryConvert ZeroValue Succeeds. - /// + /// Verifies TryConvert ZeroValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_ZeroValue_Succeeds() @@ -132,9 +106,7 @@ public async Task TryConvert_ZeroValue_Succeeds() await Assert.That(output).IsEqualTo(0.0); } - /// - /// Verifies TryConvert NegativeValue Succeeds. - /// + /// Verifies TryConvert NegativeValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NegativeValue_Succeeds() @@ -147,9 +119,7 @@ public async Task TryConvert_NegativeValue_Succeeds() await Assert.That(output).IsEqualTo(NegativeDouble); } - /// - /// Verifies TryConvertTyped ValidString Succeeds. - /// + /// Verifies TryConvertTyped ValidString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_ValidString_Succeeds() @@ -162,24 +132,20 @@ public async Task TryConvertTyped_ValidString_Succeeds() await Assert.That(output).IsEqualTo(TypedDouble); } - /// - /// Verifies TryConvertTyped InvalidType ReturnsFalse. - /// + /// Verifies TryConvertTyped InvalidType ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_InvalidType_ReturnsFalse() { var converter = new StringToDoubleTypeConverter(); - var result = converter.TryConvertTyped(123.456, null, out var output); + var result = converter.TryConvertTyped(ParsedDouble, null, out var output); await Assert.That(result).IsFalse(); await Assert.That(output).IsNull(); } - /// - /// Verifies TryConvertTyped NullInput ReturnsFalse. - /// + /// Verifies TryConvertTyped NullInput ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_NullInput_ReturnsFalse() @@ -192,9 +158,7 @@ public async Task TryConvertTyped_NullInput_ReturnsFalse() await Assert.That(output).IsNull(); } - /// - /// Verifies FromType ReturnsStringType. - /// + /// Verifies FromType ReturnsStringType. /// A task representing the asynchronous operation. [Test] public async Task FromType_ReturnsStringType() @@ -204,9 +168,7 @@ public async Task FromType_ReturnsStringType() await Assert.That(converter.FromType).IsEqualTo(typeof(string)); } - /// - /// Verifies ToType ReturnsDoubleType. - /// + /// Verifies ToType ReturnsDoubleType. /// A task representing the asynchronous operation. [Test] public async Task ToType_ReturnsDoubleType() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToGuidTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToGuidTypeConverterTests.cs index ba7c540..6ad41cf 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToGuidTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToGuidTypeConverterTests.cs @@ -4,19 +4,13 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to Guid. -/// +/// Tests for converting strings to Guid. public class StringToGuidTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,9 +20,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert ValidString Succeeds. - /// + /// Verifies TryConvert ValidString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_ValidString_Succeeds() @@ -42,9 +34,7 @@ public async Task TryConvert_ValidString_Succeeds() await Assert.That(output).IsEqualTo(expected); } - /// - /// Verifies TryConvert EmptyGuidString Succeeds. - /// + /// Verifies TryConvert EmptyGuidString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyGuidString_Succeeds() @@ -57,9 +47,7 @@ public async Task TryConvert_EmptyGuidString_Succeeds() await Assert.That(output).IsEqualTo(Guid.Empty); } - /// - /// Verifies TryConvert Null ReturnsFalse. - /// + /// Verifies TryConvert Null ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsFalse() @@ -70,9 +58,7 @@ public async Task TryConvert_Null_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert EmptyString ReturnsFalse. - /// + /// Verifies TryConvert EmptyString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_ReturnsFalse() @@ -83,9 +69,7 @@ public async Task TryConvert_EmptyString_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert InvalidString ReturnsFalse. - /// + /// Verifies TryConvert InvalidString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_InvalidString_ReturnsFalse() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToIntegerTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToIntegerTypeConverterTests.cs index 3a4fa9d..b5900c2 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToIntegerTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToIntegerTypeConverterTests.cs @@ -4,34 +4,25 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to integers. -/// +/// Tests for converting strings to integers. public class StringToIntegerTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// A value outside the target type's range, so conversion must fail. + private const double OutOfRangeValue = 123.456; + + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Integer value parsed from a positive numeric string. - /// + /// Integer value parsed from a positive numeric string. private const int ParsedInteger = 123_456; - /// - /// Integer value parsed from a negative numeric string. - /// + /// Integer value parsed from a negative numeric string. private const int NegativeInteger = -123_456; - /// - /// Integer value parsed in the typed conversion test. - /// + /// Integer value parsed in the typed conversion test. private const int TypedInteger = 789; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -41,9 +32,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert EmptyString ReturnsFalse. - /// + /// Verifies TryConvert EmptyString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_ReturnsFalse() @@ -54,9 +43,7 @@ public async Task TryConvert_EmptyString_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert InvalidString ReturnsFalse. - /// + /// Verifies TryConvert InvalidString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_InvalidString_ReturnsFalse() @@ -67,9 +54,7 @@ public async Task TryConvert_InvalidString_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert OutOfRangeValue ReturnsFalse. - /// + /// Verifies TryConvert OutOfRangeValue ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_OutOfRangeValue_ReturnsFalse() @@ -80,9 +65,7 @@ public async Task TryConvert_OutOfRangeValue_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert StringToInt Succeeds. - /// + /// Verifies TryConvert StringToInt Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_StringToInt_Succeeds() @@ -95,9 +78,7 @@ public async Task TryConvert_StringToInt_Succeeds() await Assert.That(output).IsEqualTo(ParsedInteger); } - /// - /// Verifies TryConvert NullString ReturnsFalse. - /// + /// Verifies TryConvert NullString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NullString_ReturnsFalse() @@ -110,9 +91,7 @@ public async Task TryConvert_NullString_ReturnsFalse() await Assert.That(output).IsEqualTo(0); } - /// - /// Verifies TryConvert ZeroValue Succeeds. - /// + /// Verifies TryConvert ZeroValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_ZeroValue_Succeeds() @@ -125,9 +104,7 @@ public async Task TryConvert_ZeroValue_Succeeds() await Assert.That(output).IsEqualTo(0); } - /// - /// Verifies TryConvert NegativeValue Succeeds. - /// + /// Verifies TryConvert NegativeValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NegativeValue_Succeeds() @@ -140,9 +117,7 @@ public async Task TryConvert_NegativeValue_Succeeds() await Assert.That(output).IsEqualTo(NegativeInteger); } - /// - /// Verifies TryConvertTyped ValidString Succeeds. - /// + /// Verifies TryConvertTyped ValidString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_ValidString_Succeeds() @@ -155,24 +130,20 @@ public async Task TryConvertTyped_ValidString_Succeeds() await Assert.That(output).IsEqualTo(TypedInteger); } - /// - /// Verifies TryConvertTyped InvalidType ReturnsFalse. - /// + /// Verifies TryConvertTyped InvalidType ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_InvalidType_ReturnsFalse() { var converter = new StringToIntegerTypeConverter(); - var result = converter.TryConvertTyped(123.456, null, out var output); + var result = converter.TryConvertTyped(OutOfRangeValue, null, out var output); await Assert.That(result).IsFalse(); await Assert.That(output).IsNull(); } - /// - /// Verifies TryConvertTyped NullInput ReturnsFalse. - /// + /// Verifies TryConvertTyped NullInput ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_NullInput_ReturnsFalse() @@ -185,9 +156,7 @@ public async Task TryConvertTyped_NullInput_ReturnsFalse() await Assert.That(output).IsNull(); } - /// - /// Verifies FromType ReturnsStringType. - /// + /// Verifies FromType ReturnsStringType. /// A task representing the asynchronous operation. [Test] public async Task FromType_ReturnsStringType() @@ -197,9 +166,7 @@ public async Task FromType_ReturnsStringType() await Assert.That(converter.FromType).IsEqualTo(typeof(string)); } - /// - /// Verifies ToType ReturnsIntType. - /// + /// Verifies ToType ReturnsIntType. /// A task representing the asynchronous operation. [Test] public async Task ToType_ReturnsIntType() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToLongTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToLongTypeConverterTests.cs index 7774ba0..b411b1d 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToLongTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToLongTypeConverterTests.cs @@ -4,34 +4,25 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to long integers. -/// +/// Tests for converting strings to long integers. public class StringToLongTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// A sample value used by these tests. + private const int SampleValue = 123_456; + + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Long value parsed from a positive numeric string. - /// + /// Long value parsed from a positive numeric string. private const long ParsedLong = 123_456_789_012L; - /// - /// Long value parsed from a negative numeric string. - /// + /// Long value parsed from a negative numeric string. private const long NegativeLong = -123_456_789_012L; - /// - /// Long value parsed in the typed conversion test. - /// + /// Long value parsed in the typed conversion test. private const long TypedLong = 987_654_321_098L; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -41,9 +32,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert EmptyString ReturnsFalse. - /// + /// Verifies TryConvert EmptyString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_ReturnsFalse() @@ -54,9 +43,7 @@ public async Task TryConvert_EmptyString_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert InvalidString ReturnsFalse. - /// + /// Verifies TryConvert InvalidString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_InvalidString_ReturnsFalse() @@ -67,9 +54,7 @@ public async Task TryConvert_InvalidString_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert OutOfRangeValue ReturnsFalse. - /// + /// Verifies TryConvert OutOfRangeValue ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_OutOfRangeValue_ReturnsFalse() @@ -80,9 +65,7 @@ public async Task TryConvert_OutOfRangeValue_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert StringToLong Succeeds. - /// + /// Verifies TryConvert StringToLong Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_StringToLong_Succeeds() @@ -95,9 +78,7 @@ public async Task TryConvert_StringToLong_Succeeds() await Assert.That(output).IsEqualTo(ParsedLong); } - /// - /// Verifies TryConvert NullString ReturnsFalse. - /// + /// Verifies TryConvert NullString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NullString_ReturnsFalse() @@ -110,9 +91,7 @@ public async Task TryConvert_NullString_ReturnsFalse() await Assert.That(output).IsEqualTo(0L); } - /// - /// Verifies TryConvert ZeroValue Succeeds. - /// + /// Verifies TryConvert ZeroValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_ZeroValue_Succeeds() @@ -125,9 +104,7 @@ public async Task TryConvert_ZeroValue_Succeeds() await Assert.That(output).IsEqualTo(0L); } - /// - /// Verifies TryConvert NegativeValue Succeeds. - /// + /// Verifies TryConvert NegativeValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NegativeValue_Succeeds() @@ -140,9 +117,7 @@ public async Task TryConvert_NegativeValue_Succeeds() await Assert.That(output).IsEqualTo(NegativeLong); } - /// - /// Verifies TryConvertTyped ValidString Succeeds. - /// + /// Verifies TryConvertTyped ValidString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_ValidString_Succeeds() @@ -155,24 +130,20 @@ public async Task TryConvertTyped_ValidString_Succeeds() await Assert.That(output).IsEqualTo(TypedLong); } - /// - /// Verifies TryConvertTyped InvalidType ReturnsFalse. - /// + /// Verifies TryConvertTyped InvalidType ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_InvalidType_ReturnsFalse() { var converter = new StringToLongTypeConverter(); - var result = converter.TryConvertTyped(123_456, null, out var output); + var result = converter.TryConvertTyped(SampleValue, null, out var output); await Assert.That(result).IsFalse(); await Assert.That(output).IsNull(); } - /// - /// Verifies TryConvertTyped NullInput ReturnsFalse. - /// + /// Verifies TryConvertTyped NullInput ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_NullInput_ReturnsFalse() @@ -185,9 +156,7 @@ public async Task TryConvertTyped_NullInput_ReturnsFalse() await Assert.That(output).IsNull(); } - /// - /// Verifies FromType ReturnsStringType. - /// + /// Verifies FromType ReturnsStringType. /// A task representing the asynchronous operation. [Test] public async Task FromType_ReturnsStringType() @@ -197,9 +166,7 @@ public async Task FromType_ReturnsStringType() await Assert.That(converter.FromType).IsEqualTo(typeof(string)); } - /// - /// Verifies ToType ReturnsLongType. - /// + /// Verifies ToType ReturnsLongType. /// A task representing the asynchronous operation. [Test] public async Task ToType_ReturnsLongType() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableBooleanTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableBooleanTypeConverterTests.cs index 76bcdba..1adabc4 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableBooleanTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableBooleanTypeConverterTests.cs @@ -4,19 +4,13 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to nullable booleans. -/// +/// Tests for converting strings to nullable booleans. public class StringToNullableBooleanTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,9 +20,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert TrueString Succeeds. - /// + /// Verifies TryConvert TrueString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_TrueString_Succeeds() @@ -41,9 +33,7 @@ public async Task TryConvert_TrueString_Succeeds() await Assert.That(output).IsTrue(); } - /// - /// Verifies TryConvert FalseString Succeeds. - /// + /// Verifies TryConvert FalseString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_FalseString_Succeeds() @@ -56,9 +46,7 @@ public async Task TryConvert_FalseString_Succeeds() await Assert.That(output).IsFalse(); } - /// - /// Verifies TryConvert TrueLowercase Succeeds. - /// + /// Verifies TryConvert TrueLowercase Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_TrueLowercase_Succeeds() @@ -71,9 +59,7 @@ public async Task TryConvert_TrueLowercase_Succeeds() await Assert.That(output).IsTrue(); } - /// - /// Verifies TryConvert FalseLowercase Succeeds. - /// + /// Verifies TryConvert FalseLowercase Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_FalseLowercase_Succeeds() @@ -86,9 +72,7 @@ public async Task TryConvert_FalseLowercase_Succeeds() await Assert.That(output).IsFalse(); } - /// - /// Verifies TryConvert Null ReturnsNull. - /// + /// Verifies TryConvert Null ReturnsNull. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsNull() @@ -101,9 +85,7 @@ public async Task TryConvert_Null_ReturnsNull() await Assert.That(output).IsNull(); } - /// - /// Verifies TryConvert EmptyString ReturnsNull. - /// + /// Verifies TryConvert EmptyString ReturnsNull. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_ReturnsNull() @@ -116,9 +98,7 @@ public async Task TryConvert_EmptyString_ReturnsNull() await Assert.That(output).IsNull(); } - /// - /// Verifies TryConvert InvalidString ReturnsFalse. - /// + /// Verifies TryConvert InvalidString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_InvalidString_ReturnsFalse() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableByteTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableByteTypeConverterTests.cs index a193a23..2dc7249 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableByteTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableByteTypeConverterTests.cs @@ -4,24 +4,16 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to nullable bytes. -/// +/// Tests for converting strings to nullable bytes. public class StringToNullableByteTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Byte value parsed from a typical numeric string. - /// + /// Byte value parsed from a typical numeric string. private const byte ParsedByte = 123; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -31,9 +23,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert EmptyString ReturnsTrue. - /// + /// Verifies TryConvert EmptyString ReturnsTrue. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_ReturnsTrue() @@ -44,9 +34,7 @@ public async Task TryConvert_EmptyString_ReturnsTrue() await Assert.That(result).IsTrue(); } - /// - /// Verifies TryConvert InvalidString ReturnsFalse. - /// + /// Verifies TryConvert InvalidString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_InvalidString_ReturnsFalse() @@ -57,9 +45,7 @@ public async Task TryConvert_InvalidString_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert NegativeValue ReturnsFalse. - /// + /// Verifies TryConvert NegativeValue ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NegativeValue_ReturnsFalse() @@ -70,9 +56,7 @@ public async Task TryConvert_NegativeValue_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert OutOfRangeValue ReturnsFalse. - /// + /// Verifies TryConvert OutOfRangeValue ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_OutOfRangeValue_ReturnsFalse() @@ -83,9 +67,7 @@ public async Task TryConvert_OutOfRangeValue_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert StringToByteNullable Succeeds. - /// + /// Verifies TryConvert StringToByteNullable Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_StringToByteNullable_Succeeds() @@ -95,6 +77,6 @@ public async Task TryConvert_StringToByteNullable_Succeeds() var result = converter.TryConvert("123", null, out var output); await Assert.That(result).IsTrue(); - await Assert.That(output).IsEqualTo((byte)ParsedByte); + await Assert.That(output).IsEqualTo(ParsedByte); } } diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableDateOnlyTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableDateOnlyTypeConverterTests.cs index 45d0b71..bab2949 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableDateOnlyTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableDateOnlyTypeConverterTests.cs @@ -5,19 +5,19 @@ #if NET6_0_OR_GREATER namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to nullable DateOnly. -/// +/// Tests for converting strings to nullable DateOnly. public class StringToNullableDateOnlyTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Year component of the sample date used across the conversion round-trips. + private const int SampleYear = 2_024; + + /// Day component of the sample date used across the conversion round-trips. + private const int SampleDay = 15; + + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -27,15 +27,13 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert ValidString Succeeds. - /// + /// Verifies TryConvert ValidString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_ValidString_Succeeds() { var converter = new StringToNullableDateOnlyTypeConverter(); - var expected = new DateOnly(2_024, 1, 15); + var expected = new DateOnly(SampleYear, 1, SampleDay); var result = converter.TryConvert(expected.ToString(), null, out var output); @@ -43,9 +41,7 @@ public async Task TryConvert_ValidString_Succeeds() await Assert.That(output).IsEqualTo(expected); } - /// - /// Verifies TryConvert Null ReturnsNull. - /// + /// Verifies TryConvert Null ReturnsNull. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsNull() @@ -58,9 +54,7 @@ public async Task TryConvert_Null_ReturnsNull() await Assert.That(output).IsNull(); } - /// - /// Verifies TryConvert EmptyString ReturnsNull. - /// + /// Verifies TryConvert EmptyString ReturnsNull. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_ReturnsNull() @@ -73,9 +67,7 @@ public async Task TryConvert_EmptyString_ReturnsNull() await Assert.That(output).IsNull(); } - /// - /// Verifies TryConvert InvalidString ReturnsFalse. - /// + /// Verifies TryConvert InvalidString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_InvalidString_ReturnsFalse() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableDateTimeOffsetTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableDateTimeOffsetTypeConverterTests.cs index 479bbfe..62fd6b5 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableDateTimeOffsetTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableDateTimeOffsetTypeConverterTests.cs @@ -4,19 +4,13 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to nullable DateTimeOffset. -/// +/// Tests for converting strings to nullable DateTimeOffset. public class StringToNullableDateTimeOffsetTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,9 +20,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert ValidString Succeeds. - /// + /// Verifies TryConvert ValidString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_ValidString_Succeeds() @@ -42,9 +34,7 @@ public async Task TryConvert_ValidString_Succeeds() await Assert.That(output).IsEqualTo(expected); } - /// - /// Verifies TryConvert Null ReturnsNull. - /// + /// Verifies TryConvert Null ReturnsNull. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsNull() @@ -57,9 +47,7 @@ public async Task TryConvert_Null_ReturnsNull() await Assert.That(output).IsNull(); } - /// - /// Verifies TryConvert EmptyString ReturnsNull. - /// + /// Verifies TryConvert EmptyString ReturnsNull. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_ReturnsNull() @@ -72,9 +60,7 @@ public async Task TryConvert_EmptyString_ReturnsNull() await Assert.That(output).IsNull(); } - /// - /// Verifies TryConvert InvalidString ReturnsFalse. - /// + /// Verifies TryConvert InvalidString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_InvalidString_ReturnsFalse() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableDateTimeTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableDateTimeTypeConverterTests.cs index aa948ff..e64b6b1 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableDateTimeTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableDateTimeTypeConverterTests.cs @@ -4,19 +4,13 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to nullable DateTime. -/// +/// Tests for converting strings to nullable DateTime. public class StringToNullableDateTimeTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,12 +20,9 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert ValidString Succeeds. - /// + /// Verifies TryConvert ValidString Succeeds. /// A task representing the asynchronous operation. [Test] - [SuppressMessage("Major Code Smell", "S6566:Use \"DateTimeOffset\" instead of \"DateTime\"", Justification = "Test data.")] public async Task TryConvert_ValidString_Succeeds() { var converter = new StringToNullableDateTimeTypeConverter(); @@ -43,9 +34,7 @@ public async Task TryConvert_ValidString_Succeeds() await Assert.That(output).IsEqualTo(expected); } - /// - /// Verifies TryConvert Null ReturnsNull. - /// + /// Verifies TryConvert Null ReturnsNull. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsNull() @@ -58,9 +47,7 @@ public async Task TryConvert_Null_ReturnsNull() await Assert.That(output).IsNull(); } - /// - /// Verifies TryConvert EmptyString ReturnsNull. - /// + /// Verifies TryConvert EmptyString ReturnsNull. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_ReturnsNull() @@ -73,9 +60,7 @@ public async Task TryConvert_EmptyString_ReturnsNull() await Assert.That(output).IsNull(); } - /// - /// Verifies TryConvert InvalidString ReturnsFalse. - /// + /// Verifies TryConvert InvalidString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_InvalidString_ReturnsFalse() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableDecimalTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableDecimalTypeConverterTests.cs index 4a070d0..827620a 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableDecimalTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableDecimalTypeConverterTests.cs @@ -4,24 +4,16 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to nullable decimals. -/// +/// Tests for converting strings to nullable decimals. public class StringToNullableDecimalTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Decimal value parsed from a positive numeric string. - /// - private const decimal ParsedDecimal = 123.456m; + /// Decimal value parsed from a positive numeric string. + private const decimal ParsedDecimal = 123.456M; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -31,9 +23,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert EmptyString ReturnsTrue. - /// + /// Verifies TryConvert EmptyString ReturnsTrue. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_ReturnsTrue() @@ -44,9 +34,7 @@ public async Task TryConvert_EmptyString_ReturnsTrue() await Assert.That(result).IsTrue(); } - /// - /// Verifies TryConvert InvalidString ReturnsFalse. - /// + /// Verifies TryConvert InvalidString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_InvalidString_ReturnsFalse() @@ -57,9 +45,7 @@ public async Task TryConvert_InvalidString_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert StringToDecimalNullable Succeeds. - /// + /// Verifies TryConvert StringToDecimalNullable Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_StringToDecimalNullable_Succeeds() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableDoubleTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableDoubleTypeConverterTests.cs index ed983a3..f5c28c3 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableDoubleTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableDoubleTypeConverterTests.cs @@ -4,29 +4,19 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to nullable doubles. -/// +/// Tests for converting strings to nullable doubles. public class StringToNullableDoubleTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Double value parsed from scientific notation. - /// + /// Double value parsed from scientific notation. private const double ScientificDouble = 1.23E+10; - /// - /// Double value parsed from a positive numeric string. - /// + /// Double value parsed from a positive numeric string. private const double ParsedDouble = 123.456; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -36,9 +26,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert EmptyString ReturnsTrue. - /// + /// Verifies TryConvert EmptyString ReturnsTrue. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_ReturnsTrue() @@ -49,9 +37,7 @@ public async Task TryConvert_EmptyString_ReturnsTrue() await Assert.That(result).IsTrue(); } - /// - /// Verifies TryConvert InvalidString ReturnsFalse. - /// + /// Verifies TryConvert InvalidString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_InvalidString_ReturnsFalse() @@ -62,9 +48,7 @@ public async Task TryConvert_InvalidString_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert ScientificNotation Succeeds. - /// + /// Verifies TryConvert ScientificNotation Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_ScientificNotation_Succeeds() @@ -77,9 +61,7 @@ public async Task TryConvert_ScientificNotation_Succeeds() await Assert.That(output).IsEqualTo(ScientificDouble); } - /// - /// Verifies TryConvert StringToDoubleNullable Succeeds. - /// + /// Verifies TryConvert StringToDoubleNullable Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_StringToDoubleNullable_Succeeds() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableGuidTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableGuidTypeConverterTests.cs index ad37481..c2c9259 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableGuidTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableGuidTypeConverterTests.cs @@ -4,19 +4,13 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to nullable Guid. -/// +/// Tests for converting strings to nullable Guid. public class StringToNullableGuidTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,9 +20,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert ValidString Succeeds. - /// + /// Verifies TryConvert ValidString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_ValidString_Succeeds() @@ -42,9 +34,7 @@ public async Task TryConvert_ValidString_Succeeds() await Assert.That(output).IsEqualTo(expected); } - /// - /// Verifies TryConvert Null ReturnsNull. - /// + /// Verifies TryConvert Null ReturnsNull. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsNull() @@ -57,9 +47,7 @@ public async Task TryConvert_Null_ReturnsNull() await Assert.That(output).IsNull(); } - /// - /// Verifies TryConvert EmptyString ReturnsNull. - /// + /// Verifies TryConvert EmptyString ReturnsNull. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_ReturnsNull() @@ -72,9 +60,7 @@ public async Task TryConvert_EmptyString_ReturnsNull() await Assert.That(output).IsNull(); } - /// - /// Verifies TryConvert InvalidString ReturnsFalse. - /// + /// Verifies TryConvert InvalidString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_InvalidString_ReturnsFalse() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableIntegerTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableIntegerTypeConverterTests.cs index b777a2b..cab71b3 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableIntegerTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableIntegerTypeConverterTests.cs @@ -4,24 +4,16 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to nullable integers. -/// +/// Tests for converting strings to nullable integers. public class StringToNullableIntegerTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Integer value parsed from a positive numeric string. - /// + /// Integer value parsed from a positive numeric string. private const int ParsedInteger = 123_456; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -31,9 +23,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert EmptyString ReturnsTrue. - /// + /// Verifies TryConvert EmptyString ReturnsTrue. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_ReturnsTrue() @@ -44,9 +34,7 @@ public async Task TryConvert_EmptyString_ReturnsTrue() await Assert.That(result).IsTrue(); } - /// - /// Verifies TryConvert InvalidString ReturnsFalse. - /// + /// Verifies TryConvert InvalidString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_InvalidString_ReturnsFalse() @@ -57,9 +45,7 @@ public async Task TryConvert_InvalidString_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert OutOfRangeValue ReturnsFalse. - /// + /// Verifies TryConvert OutOfRangeValue ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_OutOfRangeValue_ReturnsFalse() @@ -70,9 +56,7 @@ public async Task TryConvert_OutOfRangeValue_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert StringToIntNullable Succeeds. - /// + /// Verifies TryConvert StringToIntNullable Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_StringToIntNullable_Succeeds() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableLongTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableLongTypeConverterTests.cs index 27f859c..abde72b 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableLongTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableLongTypeConverterTests.cs @@ -4,24 +4,16 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to nullable long integers. -/// +/// Tests for converting strings to nullable long integers. public class StringToNullableLongTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Long value parsed from a positive numeric string. - /// + /// Long value parsed from a positive numeric string. private const long ParsedLong = 123_456_789_012L; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -31,9 +23,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert EmptyString ReturnsTrue. - /// + /// Verifies TryConvert EmptyString ReturnsTrue. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_ReturnsTrue() @@ -44,9 +34,7 @@ public async Task TryConvert_EmptyString_ReturnsTrue() await Assert.That(result).IsTrue(); } - /// - /// Verifies TryConvert InvalidString ReturnsFalse. - /// + /// Verifies TryConvert InvalidString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_InvalidString_ReturnsFalse() @@ -57,9 +45,7 @@ public async Task TryConvert_InvalidString_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert OutOfRangeValue ReturnsFalse. - /// + /// Verifies TryConvert OutOfRangeValue ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_OutOfRangeValue_ReturnsFalse() @@ -70,9 +56,7 @@ public async Task TryConvert_OutOfRangeValue_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert StringToLongNullable Succeeds. - /// + /// Verifies TryConvert StringToLongNullable Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_StringToLongNullable_Succeeds() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableShortTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableShortTypeConverterTests.cs index 01523c8..e5ce40c 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableShortTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableShortTypeConverterTests.cs @@ -4,24 +4,16 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to nullable short integers. -/// +/// Tests for converting strings to nullable short integers. public class StringToNullableShortTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Short value parsed from a positive numeric string. - /// + /// Short value parsed from a positive numeric string. private const short ParsedShort = 12_345; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -31,9 +23,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert EmptyString ReturnsTrue. - /// + /// Verifies TryConvert EmptyString ReturnsTrue. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_ReturnsTrue() @@ -44,9 +34,7 @@ public async Task TryConvert_EmptyString_ReturnsTrue() await Assert.That(result).IsTrue(); } - /// - /// Verifies TryConvert InvalidString ReturnsFalse. - /// + /// Verifies TryConvert InvalidString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_InvalidString_ReturnsFalse() @@ -57,9 +45,7 @@ public async Task TryConvert_InvalidString_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert OutOfRangeValue ReturnsFalse. - /// + /// Verifies TryConvert OutOfRangeValue ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_OutOfRangeValue_ReturnsFalse() @@ -70,9 +56,7 @@ public async Task TryConvert_OutOfRangeValue_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert StringToShortNullable Succeeds. - /// + /// Verifies TryConvert StringToShortNullable Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_StringToShortNullable_Succeeds() @@ -82,6 +66,6 @@ public async Task TryConvert_StringToShortNullable_Succeeds() var result = converter.TryConvert("12345", null, out var output); await Assert.That(result).IsTrue(); - await Assert.That(output).IsEqualTo((short)ParsedShort); + await Assert.That(output).IsEqualTo(ParsedShort); } } diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableSingleTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableSingleTypeConverterTests.cs index 7d30ff6..d6eb646 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableSingleTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableSingleTypeConverterTests.cs @@ -4,29 +4,19 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to nullable floats (single-precision). -/// +/// Tests for converting strings to nullable floats (single-precision). public class StringToNullableSingleTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Single value parsed from a positive numeric string. - /// - private const float ParsedSingle = 123.456f; + /// Single value parsed from a positive numeric string. + private const float ParsedSingle = 123.456F; - /// - /// Tolerance used when comparing parsed single-precision values. - /// - private const float SingleTolerance = 0.001f; + /// Tolerance used when comparing parsed single-precision values. + private const float SingleTolerance = 0.001F; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -36,9 +26,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert EmptyString ReturnsTrue. - /// + /// Verifies TryConvert EmptyString ReturnsTrue. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_ReturnsTrue() @@ -49,9 +37,7 @@ public async Task TryConvert_EmptyString_ReturnsTrue() await Assert.That(result).IsTrue(); } - /// - /// Verifies TryConvert InvalidString ReturnsFalse. - /// + /// Verifies TryConvert InvalidString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_InvalidString_ReturnsFalse() @@ -62,9 +48,7 @@ public async Task TryConvert_InvalidString_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert StringToSingleNullable Succeeds. - /// + /// Verifies TryConvert StringToSingleNullable Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_StringToSingleNullable_Succeeds() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableTimeOnlyTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableTimeOnlyTypeConverterTests.cs index 1712f33..f802034 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableTimeOnlyTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableTimeOnlyTypeConverterTests.cs @@ -5,19 +5,19 @@ #if NET6_0_OR_GREATER namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to nullable TimeOnly. -/// +/// Tests for converting strings to nullable TimeOnly. public class StringToNullableTimeOnlyTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Hour component of the sample time used across the conversion round-trips. + private const int SampleHour = 10; + + /// Minute component of the sample time used across the conversion round-trips. + private const int SampleMinute = 30; + + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -27,15 +27,13 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert ValidString Succeeds. - /// + /// Verifies TryConvert ValidString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_ValidString_Succeeds() { var converter = new StringToNullableTimeOnlyTypeConverter(); - var expected = new TimeOnly(10, 30, 0); + var expected = new TimeOnly(SampleHour, SampleMinute, 0); var result = converter.TryConvert(expected.ToString(), null, out var output); @@ -43,9 +41,7 @@ public async Task TryConvert_ValidString_Succeeds() await Assert.That(output).IsEqualTo(expected); } - /// - /// Verifies TryConvert Null ReturnsNull. - /// + /// Verifies TryConvert Null ReturnsNull. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsNull() @@ -58,9 +54,7 @@ public async Task TryConvert_Null_ReturnsNull() await Assert.That(output).IsNull(); } - /// - /// Verifies TryConvert EmptyString ReturnsNull. - /// + /// Verifies TryConvert EmptyString ReturnsNull. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_ReturnsNull() @@ -73,9 +67,7 @@ public async Task TryConvert_EmptyString_ReturnsNull() await Assert.That(output).IsNull(); } - /// - /// Verifies TryConvert InvalidString ReturnsFalse. - /// + /// Verifies TryConvert InvalidString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_InvalidString_ReturnsFalse() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableTimeSpanTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableTimeSpanTypeConverterTests.cs index 2499ba2..71a40bb 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableTimeSpanTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToNullableTimeSpanTypeConverterTests.cs @@ -4,19 +4,16 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to nullable TimeSpan. -/// +/// Tests for converting strings to nullable TimeSpan. public class StringToNullableTimeSpanTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// The number of hours in the sample duration under test. + private const double SampleHours = 2.5; + + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,15 +23,13 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert ValidString Succeeds. - /// + /// Verifies TryConvert ValidString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_ValidString_Succeeds() { var converter = new StringToNullableTimeSpanTypeConverter(); - var expected = TimeSpan.FromHours(2.5); + var expected = TimeSpan.FromHours(SampleHours); var result = converter.TryConvert(expected.ToString(), null, out var output); @@ -42,9 +37,7 @@ public async Task TryConvert_ValidString_Succeeds() await Assert.That(output).IsEqualTo(expected); } - /// - /// Verifies TryConvert Null ReturnsNull. - /// + /// Verifies TryConvert Null ReturnsNull. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsNull() @@ -57,9 +50,7 @@ public async Task TryConvert_Null_ReturnsNull() await Assert.That(output).IsNull(); } - /// - /// Verifies TryConvert EmptyString ReturnsNull. - /// + /// Verifies TryConvert EmptyString ReturnsNull. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_ReturnsNull() @@ -72,9 +63,7 @@ public async Task TryConvert_EmptyString_ReturnsNull() await Assert.That(output).IsNull(); } - /// - /// Verifies TryConvert InvalidString ReturnsFalse. - /// + /// Verifies TryConvert InvalidString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_InvalidString_ReturnsFalse() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToShortTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToShortTypeConverterTests.cs index e0aab53..488a736 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToShortTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToShortTypeConverterTests.cs @@ -4,34 +4,25 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to short integers. -/// +/// Tests for converting strings to short integers. public class StringToShortTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// A sample value used by these tests. + private const int SampleValue = 1_234; + + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Short value parsed from a positive numeric string. - /// + /// Short value parsed from a positive numeric string. private const short ParsedShort = 12_345; - /// - /// Short value parsed from a negative numeric string. - /// + /// Short value parsed from a negative numeric string. private const short NegativeShort = -12_345; - /// - /// Short value parsed in the typed conversion test. - /// + /// Short value parsed in the typed conversion test. private const short TypedShort = 1_000; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -41,9 +32,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert EmptyString ReturnsFalse. - /// + /// Verifies TryConvert EmptyString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_ReturnsFalse() @@ -54,9 +43,7 @@ public async Task TryConvert_EmptyString_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert InvalidString ReturnsFalse. - /// + /// Verifies TryConvert InvalidString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_InvalidString_ReturnsFalse() @@ -67,9 +54,7 @@ public async Task TryConvert_InvalidString_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert OutOfRangeValue ReturnsFalse. - /// + /// Verifies TryConvert OutOfRangeValue ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_OutOfRangeValue_ReturnsFalse() @@ -80,9 +65,7 @@ public async Task TryConvert_OutOfRangeValue_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert StringToShort Succeeds. - /// + /// Verifies TryConvert StringToShort Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_StringToShort_Succeeds() @@ -92,12 +75,10 @@ public async Task TryConvert_StringToShort_Succeeds() var result = converter.TryConvert("12345", null, out var output); await Assert.That(result).IsTrue(); - await Assert.That(output).IsEqualTo((short)ParsedShort); + await Assert.That(output).IsEqualTo(ParsedShort); } - /// - /// Verifies TryConvert NullString ReturnsFalse. - /// + /// Verifies TryConvert NullString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NullString_ReturnsFalse() @@ -110,9 +91,7 @@ public async Task TryConvert_NullString_ReturnsFalse() await Assert.That(output).IsEqualTo((short)0); } - /// - /// Verifies TryConvert ZeroValue Succeeds. - /// + /// Verifies TryConvert ZeroValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_ZeroValue_Succeeds() @@ -125,9 +104,7 @@ public async Task TryConvert_ZeroValue_Succeeds() await Assert.That(output).IsEqualTo((short)0); } - /// - /// Verifies TryConvert NegativeValue Succeeds. - /// + /// Verifies TryConvert NegativeValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NegativeValue_Succeeds() @@ -137,12 +114,10 @@ public async Task TryConvert_NegativeValue_Succeeds() var result = converter.TryConvert("-12345", null, out var output); await Assert.That(result).IsTrue(); - await Assert.That(output).IsEqualTo((short)NegativeShort); + await Assert.That(output).IsEqualTo(NegativeShort); } - /// - /// Verifies TryConvertTyped ValidString Succeeds. - /// + /// Verifies TryConvertTyped ValidString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_ValidString_Succeeds() @@ -152,27 +127,23 @@ public async Task TryConvertTyped_ValidString_Succeeds() var result = converter.TryConvertTyped("1000", null, out var output); await Assert.That(result).IsTrue(); - await Assert.That(output).IsEqualTo((short)TypedShort); + await Assert.That(output).IsEqualTo(TypedShort); } - /// - /// Verifies TryConvertTyped InvalidType ReturnsFalse. - /// + /// Verifies TryConvertTyped InvalidType ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_InvalidType_ReturnsFalse() { var converter = new StringToShortTypeConverter(); - var result = converter.TryConvertTyped(1_234, null, out var output); + var result = converter.TryConvertTyped(SampleValue, null, out var output); await Assert.That(result).IsFalse(); await Assert.That(output).IsNull(); } - /// - /// Verifies TryConvertTyped NullInput ReturnsFalse. - /// + /// Verifies TryConvertTyped NullInput ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_NullInput_ReturnsFalse() @@ -185,9 +156,7 @@ public async Task TryConvertTyped_NullInput_ReturnsFalse() await Assert.That(output).IsNull(); } - /// - /// Verifies FromType ReturnsStringType. - /// + /// Verifies FromType ReturnsStringType. /// A task representing the asynchronous operation. [Test] public async Task FromType_ReturnsStringType() @@ -197,9 +166,7 @@ public async Task FromType_ReturnsStringType() await Assert.That(converter.FromType).IsEqualTo(typeof(string)); } - /// - /// Verifies ToType ReturnsShortType. - /// + /// Verifies ToType ReturnsShortType. /// A task representing the asynchronous operation. [Test] public async Task ToType_ReturnsShortType() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToSingleTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToSingleTypeConverterTests.cs index c8e8e1a..d58049a 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToSingleTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToSingleTypeConverterTests.cs @@ -4,49 +4,31 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to floats (single-precision). -/// +/// Tests for converting strings to floats (single-precision). public class StringToSingleTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Single value parsed from a positive numeric string. - /// - private const float ParsedSingle = 123.456f; - - /// - /// Single value parsed from a negative numeric string. - /// - private const float NegativeSingle = -123.456f; - - /// - /// Single value parsed from scientific notation. - /// - private const float ScientificSingle = 1.23E+5f; - - /// - /// Single value parsed in the typed conversion test. - /// - private const float TypedSingle = 456.789f; - - /// - /// Tolerance used when comparing parsed single-precision values. - /// - private const float SingleTolerance = 0.001f; - - /// - /// Tolerance used when comparing scientific-notation single values. - /// - private const float ScientificTolerance = 0.1f; - - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Single value parsed from a positive numeric string. + private const float ParsedSingle = 123.456F; + + /// Single value parsed from a negative numeric string. + private const float NegativeSingle = -123.456F; + + /// Single value parsed from scientific notation. + private const float ScientificSingle = 1.23E+5F; + + /// Single value parsed in the typed conversion test. + private const float TypedSingle = 456.789F; + + /// Tolerance used when comparing parsed single-precision values. + private const float SingleTolerance = 0.001F; + + /// Tolerance used when comparing scientific-notation single values. + private const float ScientificTolerance = 0.1F; + + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -56,9 +38,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert EmptyString ReturnsFalse. - /// + /// Verifies TryConvert EmptyString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_ReturnsFalse() @@ -69,9 +49,7 @@ public async Task TryConvert_EmptyString_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert InvalidString ReturnsFalse. - /// + /// Verifies TryConvert InvalidString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_InvalidString_ReturnsFalse() @@ -82,9 +60,7 @@ public async Task TryConvert_InvalidString_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert StringToSingle Succeeds. - /// + /// Verifies TryConvert StringToSingle Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_StringToSingle_Succeeds() @@ -97,9 +73,7 @@ public async Task TryConvert_StringToSingle_Succeeds() await Assert.That(output).IsEqualTo(ParsedSingle).Within(SingleTolerance); } - /// - /// Verifies TryConvert NullString ReturnsFalse. - /// + /// Verifies TryConvert NullString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NullString_ReturnsFalse() @@ -109,12 +83,10 @@ public async Task TryConvert_NullString_ReturnsFalse() var result = converter.TryConvert(null, null, out var output); await Assert.That(result).IsFalse(); - await Assert.That(output).IsEqualTo(0.0f); + await Assert.That(output).IsEqualTo(0.0F); } - /// - /// Verifies TryConvert ZeroValue Succeeds. - /// + /// Verifies TryConvert ZeroValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_ZeroValue_Succeeds() @@ -124,12 +96,10 @@ public async Task TryConvert_ZeroValue_Succeeds() var result = converter.TryConvert("0", null, out var output); await Assert.That(result).IsTrue(); - await Assert.That(output).IsEqualTo(0.0f); + await Assert.That(output).IsEqualTo(0.0F); } - /// - /// Verifies TryConvert NegativeValue Succeeds. - /// + /// Verifies TryConvert NegativeValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NegativeValue_Succeeds() @@ -142,9 +112,7 @@ public async Task TryConvert_NegativeValue_Succeeds() await Assert.That(output).IsEqualTo(NegativeSingle).Within(SingleTolerance); } - /// - /// Verifies TryConvert ScientificNotation Succeeds. - /// + /// Verifies TryConvert ScientificNotation Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_ScientificNotation_Succeeds() @@ -157,9 +125,7 @@ public async Task TryConvert_ScientificNotation_Succeeds() await Assert.That(output).IsEqualTo(ScientificSingle).Within(ScientificTolerance); } - /// - /// Verifies TryConvertTyped ValidString Succeeds. - /// + /// Verifies TryConvertTyped ValidString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_ValidString_Succeeds() @@ -173,24 +139,20 @@ public async Task TryConvertTyped_ValidString_Succeeds() await Assert.That((float)output!).IsEqualTo(TypedSingle).Within(SingleTolerance); } - /// - /// Verifies TryConvertTyped InvalidType ReturnsFalse. - /// + /// Verifies TryConvertTyped InvalidType ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_InvalidType_ReturnsFalse() { var converter = new StringToSingleTypeConverter(); - var result = converter.TryConvertTyped(123.456, null, out var output); + var result = converter.TryConvertTyped(ParsedSingle, null, out var output); await Assert.That(result).IsFalse(); await Assert.That(output).IsNull(); } - /// - /// Verifies TryConvertTyped NullInput ReturnsFalse. - /// + /// Verifies TryConvertTyped NullInput ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvertTyped_NullInput_ReturnsFalse() @@ -203,9 +165,7 @@ public async Task TryConvertTyped_NullInput_ReturnsFalse() await Assert.That(output).IsNull(); } - /// - /// Verifies FromType ReturnsStringType. - /// + /// Verifies FromType ReturnsStringType. /// A task representing the asynchronous operation. [Test] public async Task FromType_ReturnsStringType() @@ -215,9 +175,7 @@ public async Task FromType_ReturnsStringType() await Assert.That(converter.FromType).IsEqualTo(typeof(string)); } - /// - /// Verifies ToType ReturnsFloatType. - /// + /// Verifies ToType ReturnsFloatType. /// A task representing the asynchronous operation. [Test] public async Task ToType_ReturnsFloatType() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToTimeOnlyTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToTimeOnlyTypeConverterTests.cs index 4a21598..c73ace0 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToTimeOnlyTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToTimeOnlyTypeConverterTests.cs @@ -5,19 +5,19 @@ #if NET6_0_OR_GREATER namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to TimeOnly. -/// +/// Tests for converting strings to TimeOnly. public class StringToTimeOnlyTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Hour component of the sample time used across the conversion round-trips. + private const int SampleHour = 10; + + /// Minute component of the sample time used across the conversion round-trips. + private const int SampleMinute = 30; + + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -27,15 +27,13 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert ValidString Succeeds. - /// + /// Verifies TryConvert ValidString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_ValidString_Succeeds() { var converter = new StringToTimeOnlyTypeConverter(); - var expected = new TimeOnly(10, 30, 0); + var expected = new TimeOnly(SampleHour, SampleMinute, 0); var result = converter.TryConvert(expected.ToString(), null, out var output); @@ -43,9 +41,7 @@ public async Task TryConvert_ValidString_Succeeds() await Assert.That(output).IsEqualTo(expected); } - /// - /// Verifies TryConvert Null ReturnsFalse. - /// + /// Verifies TryConvert Null ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsFalse() @@ -56,9 +52,7 @@ public async Task TryConvert_Null_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert EmptyString ReturnsFalse. - /// + /// Verifies TryConvert EmptyString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_ReturnsFalse() @@ -69,9 +63,7 @@ public async Task TryConvert_EmptyString_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert InvalidString ReturnsFalse. - /// + /// Verifies TryConvert InvalidString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_InvalidString_ReturnsFalse() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToTimeSpanTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToTimeSpanTypeConverterTests.cs index d25dc82..8157aee 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToTimeSpanTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToTimeSpanTypeConverterTests.cs @@ -4,19 +4,16 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to TimeSpan. -/// +/// Tests for converting strings to TimeSpan. public class StringToTimeSpanTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// The number of hours in the sample duration under test. + private const double SampleHours = 2.5; + + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,15 +23,13 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert ValidString Succeeds. - /// + /// Verifies TryConvert ValidString Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_ValidString_Succeeds() { var converter = new StringToTimeSpanTypeConverter(); - var expected = TimeSpan.FromHours(2.5); + var expected = TimeSpan.FromHours(SampleHours); var result = converter.TryConvert(expected.ToString(), null, out var output); @@ -42,9 +37,7 @@ public async Task TryConvert_ValidString_Succeeds() await Assert.That(output).IsEqualTo(expected); } - /// - /// Verifies TryConvert ZeroTimeSpan Succeeds. - /// + /// Verifies TryConvert ZeroTimeSpan Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_ZeroTimeSpan_Succeeds() @@ -57,9 +50,7 @@ public async Task TryConvert_ZeroTimeSpan_Succeeds() await Assert.That(output).IsEqualTo(TimeSpan.Zero); } - /// - /// Verifies TryConvert Null ReturnsFalse. - /// + /// Verifies TryConvert Null ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsFalse() @@ -70,9 +61,7 @@ public async Task TryConvert_Null_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert EmptyString ReturnsFalse. - /// + /// Verifies TryConvert EmptyString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_ReturnsFalse() @@ -83,9 +72,7 @@ public async Task TryConvert_EmptyString_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert InvalidString ReturnsFalse. - /// + /// Verifies TryConvert InvalidString ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_InvalidString_ReturnsFalse() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToUriTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToUriTypeConverterTests.cs index 43720a4..88f88fb 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToUriTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/StringToUriTypeConverterTests.cs @@ -4,19 +4,13 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting strings to Uri. -/// +/// Tests for converting strings to Uri. public class StringToUriTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,9 +20,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert AbsoluteUri Succeeds. - /// + /// Verifies TryConvert AbsoluteUri Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_AbsoluteUri_Succeeds() @@ -42,9 +34,7 @@ public async Task TryConvert_AbsoluteUri_Succeeds() await Assert.That(output).IsEqualTo(expected); } - /// - /// Verifies TryConvert RelativeUri Succeeds. - /// + /// Verifies TryConvert RelativeUri Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_RelativeUri_Succeeds() @@ -58,9 +48,7 @@ public async Task TryConvert_RelativeUri_Succeeds() await Assert.That(output).IsEqualTo(expected); } - /// - /// Verifies TryConvert Null ReturnsFalse. - /// + /// Verifies TryConvert Null ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsFalse() @@ -71,9 +59,7 @@ public async Task TryConvert_Null_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies TryConvert EmptyString CreatesRelativeUri. - /// + /// Verifies TryConvert EmptyString CreatesRelativeUri. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_EmptyString_CreatesRelativeUri() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/TimeOnlyToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/TimeOnlyToStringTypeConverterTests.cs index 01a918d..a0a48f2 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/TimeOnlyToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/TimeOnlyToStringTypeConverterTests.cs @@ -5,19 +5,22 @@ #if NET6_0_OR_GREATER namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting TimeOnly to strings. -/// +/// Tests for converting TimeOnly to strings. public class TimeOnlyToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Hour component of the sample time used across the conversion round-trips. + private const int SampleHour = 10; + + /// Minute component of the sample time used across the conversion round-trips. + private const int SampleMinute = 30; + + /// Second component of the sample time used across the conversion round-trips. + private const int SampleSecond = 45; + + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -27,15 +30,13 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert TimeOnly Succeeds. - /// + /// Verifies TryConvert TimeOnly Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_TimeOnly_Succeeds() { var converter = new TimeOnlyToStringTypeConverter(); - var value = new TimeOnly(10, 30, 45); + var value = new TimeOnly(SampleHour, SampleMinute, SampleSecond); var result = converter.TryConvert(value, null, out var output); @@ -43,9 +44,7 @@ public async Task TryConvert_TimeOnly_Succeeds() await Assert.That(output).IsEqualTo(value.ToString()); } - /// - /// Verifies TryConvert MinValue Succeeds. - /// + /// Verifies TryConvert MinValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MinValue_Succeeds() @@ -59,9 +58,7 @@ public async Task TryConvert_MinValue_Succeeds() await Assert.That(output).IsEqualTo(TimeOnly.MinValue.ToString()); } - /// - /// Verifies TryConvert MaxValue Succeeds. - /// + /// Verifies TryConvert MaxValue Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_MaxValue_Succeeds() diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/TimeSpanToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/TimeSpanToStringTypeConverterTests.cs index 2a48f23..b23d13b 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/TimeSpanToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/TimeSpanToStringTypeConverterTests.cs @@ -4,19 +4,19 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting TimeSpan to strings. -/// +/// Tests for converting TimeSpan to strings. public class TimeSpanToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// A negative duration, in minutes, used to check sign handling. + private const int NegativeMinutes = -30; + + /// The number of hours in the sample duration under test. + private const double SampleHours = 2.5; + + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,15 +26,13 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert TimeSpan Succeeds. - /// + /// Verifies TryConvert TimeSpan Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_TimeSpan_Succeeds() { var converter = new TimeSpanToStringTypeConverter(); - var value = TimeSpan.FromHours(2.5); + var value = TimeSpan.FromHours(SampleHours); var result = converter.TryConvert(value, null, out var output); @@ -42,9 +40,7 @@ public async Task TryConvert_TimeSpan_Succeeds() await Assert.That(output).IsEqualTo(value.ToString()); } - /// - /// Verifies TryConvert ZeroTimeSpan Succeeds. - /// + /// Verifies TryConvert ZeroTimeSpan Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_ZeroTimeSpan_Succeeds() @@ -58,15 +54,13 @@ public async Task TryConvert_ZeroTimeSpan_Succeeds() await Assert.That(output).IsEqualTo("00:00:00"); } - /// - /// Verifies TryConvert NegativeTimeSpan Succeeds. - /// + /// Verifies TryConvert NegativeTimeSpan Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_NegativeTimeSpan_Succeeds() { var converter = new TimeSpanToStringTypeConverter(); - var value = TimeSpan.FromMinutes(-30); + var value = TimeSpan.FromMinutes(NegativeMinutes); var result = converter.TryConvert(value, null, out var output); diff --git a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/UriToStringTypeConverterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/UriToStringTypeConverterTests.cs index 96d9c64..035b471 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/UriToStringTypeConverterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Bindings/TypeConverters/UriToStringTypeConverterTests.cs @@ -4,19 +4,13 @@ namespace ReactiveUI.Binding.Tests.Bindings.TypeConverters; -/// -/// Tests for converting Uri to strings. -/// +/// Tests for converting Uri to strings. public class UriToStringTypeConverterTests { - /// - /// Expected affinity returned for matched converter type pairs. - /// + /// Expected affinity returned for matched converter type pairs. private const int ExpectedAffinity = 2; - /// - /// Verifies GetAffinityForObjects Returns2. - /// + /// Verifies GetAffinityForObjects Returns2. /// A task representing the asynchronous operation. [Test] public async Task GetAffinityForObjects_Returns2() @@ -26,9 +20,7 @@ public async Task GetAffinityForObjects_Returns2() await Assert.That(affinity).IsEqualTo(ExpectedAffinity); } - /// - /// Verifies TryConvert AbsoluteUri Succeeds. - /// + /// Verifies TryConvert AbsoluteUri Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_AbsoluteUri_Succeeds() @@ -42,9 +34,7 @@ public async Task TryConvert_AbsoluteUri_Succeeds() await Assert.That(output).IsEqualTo("https://reactiveui.net/docs"); } - /// - /// Verifies TryConvert RelativeUri Succeeds. - /// + /// Verifies TryConvert RelativeUri Succeeds. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_RelativeUri_Succeeds() @@ -58,9 +48,7 @@ public async Task TryConvert_RelativeUri_Succeeds() await Assert.That(output).IsEqualTo("/path/to/resource"); } - /// - /// Verifies TryConvert Null ReturnsFalse. - /// + /// Verifies TryConvert Null ReturnsFalse. /// A task representing the asynchronous operation. [Test] public async Task TryConvert_Null_ReturnsFalse() diff --git a/src/tests/ReactiveUI.Binding.Tests/Builder/BuilderMixinsTests.cs b/src/tests/ReactiveUI.Binding.Tests/Builder/BuilderMixinsTests.cs index 2949639..143c11c 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Builder/BuilderMixinsTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Builder/BuilderMixinsTests.cs @@ -9,23 +9,20 @@ namespace ReactiveUI.Binding.Tests.Builder; -/// -/// Tests for the extension methods that bridge -/// to . -/// +/// Tests for the extension methods that bridge to . public class BuilderMixinsTests { - /// - /// Verifies that succeeds when the - /// is a valid . - /// + /// The value the stub converter returns. + private const int ConvertedValue = 42; + + /// Verifies that succeeds when the is a valid . /// A task representing the asynchronous test operation. [Test] public async Task BuildApp_WithValidBuilder_Succeeds() { RxBindingBuilder.ResetForTesting(); var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - builder.WithCoreServices(); + _ = builder.WithCoreServices(); IAppBuilder appBuilder = builder; var instance = appBuilder.BuildApp(); @@ -33,26 +30,19 @@ public async Task BuildApp_WithValidBuilder_Succeeds() await Assert.That(instance).IsNotNull(); } - /// - /// Verifies that throws - /// when the - /// is not an . - /// + /// Verifies that throws when the builder is not an . /// A task representing the asynchronous test operation. [Test] public async Task BuildApp_WithNonReactiveUIBuilder_ThrowsInvalidOperationException() { - IAppBuilder fakeBuilder = new FakeAppBuilder(); + var fakeBuilder = new FakeAppBuilder(); var action = () => fakeBuilder.BuildApp(); await Assert.That(action).ThrowsExactly(); } - /// - /// Verifies that delegates - /// to the underlying . - /// + /// Verifies that delegates to the underlying . /// A task representing the asynchronous test operation. [Test] public async Task WithPlatformModule_DelegatesToBuilder() @@ -64,32 +54,25 @@ public async Task WithPlatformModule_DelegatesToBuilder() IAppBuilder appBuilder = builder; var result = appBuilder.WithPlatformModule(new TestModule(() => registered = true)); - builder.BuildApp(); + _ = builder.BuildApp(); await Assert.That(registered).IsTrue(); await Assert.That(result).IsNotNull(); } - /// - /// Verifies that throws - /// when the - /// is not an . - /// + /// Verifies that throws when the builder is not an . /// A task representing the asynchronous test operation. [Test] public async Task WithPlatformModule_WithNonReactiveUIBuilder_ThrowsInvalidOperationException() { - IAppBuilder fakeBuilder = new FakeAppBuilder(); + var fakeBuilder = new FakeAppBuilder(); - var action = () => fakeBuilder.WithPlatformModule(new TestModule(() => { })); + var action = () => fakeBuilder.WithPlatformModule(new TestModule(static () => { })); await Assert.That(action).ThrowsExactly(); } - /// - /// Verifies that delegates - /// to the underlying . - /// + /// Verifies that delegates to the underlying . /// A task representing the asynchronous test operation. [Test] public async Task WithRegistration_DelegatesToBuilder() @@ -105,26 +88,19 @@ public async Task WithRegistration_DelegatesToBuilder() await Assert.That(result).IsNotNull(); } - /// - /// Verifies that throws - /// when the - /// is not an . - /// + /// Verifies that throws when the builder is not an . /// A task representing the asynchronous test operation. [Test] public async Task WithRegistration_WithNonReactiveUIBuilder_ThrowsInvalidOperationException() { - IAppBuilder fakeBuilder = new FakeAppBuilder(); + var fakeBuilder = new FakeAppBuilder(); - var action = () => fakeBuilder.WithRegistration(_ => { }); + var action = () => fakeBuilder.WithRegistration(static _ => { }); await Assert.That(action).ThrowsExactly(); } - /// - /// Verifies that registers a - /// typed converter via the extension method. - /// + /// Verifies that registers a typed converter via the extension method. /// A task representing the asynchronous test operation. [Test] public async Task WithConverter_RegistersConverterViaAppBuilder() @@ -134,7 +110,7 @@ public async Task WithConverter_RegistersConverterViaAppBuilder() var converter = new StubBindingTypeConverter( typeof(int), typeof(bool), - (_, _) => (true, true)); + static (_, _) => (true, true)); IAppBuilder appBuilder = builder; var result = appBuilder.WithConverter(converter); @@ -146,37 +122,30 @@ public async Task WithConverter_RegistersConverterViaAppBuilder() await Assert.That(ReferenceEquals(resolved, converter)).IsTrue(); } - /// - /// Verifies that throws - /// when the - /// is not an . - /// + /// Verifies that throws when the builder is not an . /// A task representing the asynchronous test operation. [Test] public async Task WithConverter_WithNonReactiveUIBuilder_ThrowsInvalidOperationException() { - IAppBuilder fakeBuilder = new FakeAppBuilder(); + var fakeBuilder = new FakeAppBuilder(); var converter = new StubBindingTypeConverter( typeof(int), typeof(bool), - (_, _) => (true, true)); + static (_, _) => (true, true)); var action = () => fakeBuilder.WithConverter(converter); await Assert.That(action).ThrowsExactly(); } - /// - /// Verifies that registers a - /// fallback converter via the extension method. - /// + /// Verifies that registers a fallback converter via the extension method. /// A task representing the asynchronous test operation. [Test] public async Task WithFallbackConverter_RegistersConverterViaAppBuilder() { RxBindingBuilder.ResetForTesting(); var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - var converter = new StubFallbackConverter((_, _, _, _) => (true, "converted")); + var converter = new StubFallbackConverter(static (_, _, _, _) => (true, "converted")); IAppBuilder appBuilder = builder; var result = appBuilder.WithFallbackConverter(converter); @@ -187,27 +156,20 @@ public async Task WithFallbackConverter_RegistersConverterViaAppBuilder() await Assert.That(allConverters).Contains(converter); } - /// - /// Verifies that throws - /// when the - /// is not an . - /// + /// Verifies that throws when the builder is not an . /// A task representing the asynchronous test operation. [Test] public async Task WithFallbackConverter_WithNonReactiveUIBuilder_ThrowsInvalidOperationException() { - IAppBuilder fakeBuilder = new FakeAppBuilder(); - var converter = new StubFallbackConverter((_, _, _, _) => (true, "converted")); + var fakeBuilder = new FakeAppBuilder(); + var converter = new StubFallbackConverter(static (_, _, _, _) => (true, "converted")); var action = () => fakeBuilder.WithFallbackConverter(converter); await Assert.That(action).ThrowsExactly(); } - /// - /// Verifies that registers a - /// set-method converter via the extension method. - /// + /// Verifies that registers a set-method converter via the extension method. /// A task representing the asynchronous test operation. [Test] public async Task WithSetMethodConverter_RegistersConverterViaAppBuilder() @@ -225,16 +187,12 @@ public async Task WithSetMethodConverter_RegistersConverterViaAppBuilder() await Assert.That(allConverters).Contains(converter); } - /// - /// Verifies that throws - /// when the - /// is not an . - /// + /// Verifies that throws when the builder is not an . /// A task representing the asynchronous test operation. [Test] public async Task WithSetMethodConverter_WithNonReactiveUIBuilder_ThrowsInvalidOperationException() { - IAppBuilder fakeBuilder = new FakeAppBuilder(); + var fakeBuilder = new FakeAppBuilder(); var converter = new StubSetMethodBindingConverter(); var action = () => fakeBuilder.WithSetMethodConverter(converter); @@ -242,10 +200,7 @@ public async Task WithSetMethodConverter_WithNonReactiveUIBuilder_ThrowsInvalidO await Assert.That(action).ThrowsExactly(); } - /// - /// Verifies that chaining multiple extension methods through - /// works correctly and returns the builder each time. - /// + /// Verifies that chaining multiple extension methods through works correctly and returns the builder each time. /// A task representing the asynchronous test operation. [Test] public async Task FluentChaining_ThroughIAppBuilder_Works() @@ -255,8 +210,8 @@ public async Task FluentChaining_ThroughIAppBuilder_Works() var converter = new StubBindingTypeConverter( typeof(string), typeof(int), - (_, _) => (true, 42)); - var fallbackConverter = new StubFallbackConverter((_, _, _, _) => (true, "fallback")); + static (_, _) => (true, ConvertedValue)); + var fallbackConverter = new StubFallbackConverter(static (_, _, _, _) => (true, "fallback")); var setConverter = new StubSetMethodBindingConverter(); IAppBuilder appBuilder = builder; @@ -274,10 +229,7 @@ await Assert.That(builder.ConverterService.SetMethodConverters.GetAllConverters( .Contains(setConverter); } - /// - /// Verifies that delegates - /// to the underlying . - /// + /// Verifies that delegates to the underlying . /// A task representing the asynchronous test operation. [Test] public async Task ConfigureViewLocator_DelegatesToBuilder() @@ -285,9 +237,9 @@ public async Task ConfigureViewLocator_DelegatesToBuilder() RxBindingBuilder.ResetForTesting(); var appBuilder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - appBuilder + _ = appBuilder .WithCoreServices() - .ConfigureViewLocator(mappings => + .ConfigureViewLocator(static mappings => mappings.Map()) .BuildApp(); @@ -297,30 +249,23 @@ public async Task ConfigureViewLocator_DelegatesToBuilder() await Assert.That(result).IsNotNull(); } - /// - /// Verifies that throws when the - /// is not an . - /// + /// Verifies that throws when the is not an . /// A task representing the asynchronous test operation. [Test] public async Task ConfigureViewLocator_WithNonReactiveUIBuilder_Throws() { - IAppBuilder fakeBuilder = new FakeAppBuilder(); + var fakeBuilder = new FakeAppBuilder(); - var action = () => fakeBuilder.ConfigureViewLocator(_ => { }); + var action = () => fakeBuilder.ConfigureViewLocator(static _ => { }); await Assert.That(action).ThrowsExactly(); } - /// - /// Simple view model for mixin testing. - /// - [SuppressMessage("Minor Code Smell", "S2094:Classes should not be empty", Justification = "Used for testing")] + /// Simple view model for mixin testing. + [SuppressMessage("Design", "SST1436:Empty type", Justification = "The tests only need a distinct view model type; members would not be exercised.")] private sealed class MixinTestViewModel; - /// - /// Simple view for mixin testing. - /// + /// Simple view for mixin testing. private sealed class MixinTestView : IViewFor { /// @@ -334,60 +279,41 @@ private sealed class MixinTestView : IViewFor } } - /// - /// A fake that does NOT implement - /// to test the guard clauses in . - /// + /// A fake that does NOT implement to test the guard clauses in . private sealed class FakeAppBuilder : IAppBuilder { - /// - /// Registers core services. - /// + /// Registers core services. /// The builder instance. public IAppBuilder WithCoreServices() => this; - /// - /// Uses the current Splat locator. - /// + /// Uses the current Splat locator. /// The builder instance. - public IAppBuilder UseCurrentSplatLocator() => this; + public IAppBuilder UseCurrentSplatLocator() => WithCoreServices(); - /// - /// Registers a module. - /// + /// Registers a module. /// The module type. - /// The module instance. + /// The module instance. /// The builder instance. - public IAppBuilder UsingModule(T module) + public IAppBuilder UsingModule(T registrationModule) where T : IModule => this; - /// - /// Registers a custom action. - /// + /// Registers a custom action. /// The configuration action. /// The builder instance. public IAppBuilder WithCustomRegistration(Action configureAction) => this; - /// - /// Builds the application instance. - /// + /// Builds the application instance. /// The application instance. public IAppInstance Build() => throw new NotSupportedException(); } - /// - /// A test that invokes a callback when configured. - /// + /// A test that invokes a callback when configured. private sealed class TestModule : IModule { - /// - /// A callback action invoked during the configuration process of the . - /// + /// A callback action invoked during the configuration process of the . private readonly Action _onConfigure; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The callback to invoke during configuration. public TestModule(Action onConfigure) => _onConfigure = onConfigure; diff --git a/src/tests/ReactiveUI.Binding.Tests/Builder/ReactiveUIBindingBuilderTests.cs b/src/tests/ReactiveUI.Binding.Tests/Builder/ReactiveUIBindingBuilderTests.cs index bd4d9d0..42b6a42 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Builder/ReactiveUIBindingBuilderTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Builder/ReactiveUIBindingBuilderTests.cs @@ -7,19 +7,13 @@ namespace ReactiveUI.Binding.Tests.Builder; -/// -/// Tests for the class. -/// +/// Tests for the class. public class ReactiveUIBindingBuilderTests { - /// - /// The minimum number of observable-for-property services expected after core registration. - /// + /// The minimum number of observable-for-property services expected after core registration. private const int MinimumCoreObservableServices = 2; - /// - /// Verifies that the builder can be created and has a non-null ConverterService. - /// + /// Verifies that the builder can be created and has a non-null ConverterService. /// A task representing the asynchronous test operation. [Test] public async Task Constructor_CreatesConverterService() @@ -30,9 +24,7 @@ public async Task Constructor_CreatesConverterService() await Assert.That(builder.ConverterService).IsNotNull(); } - /// - /// Verifies that WithCoreServices registers INPC and POCO observation services. - /// + /// Verifies that WithCoreServices registers INPC and POCO observation services. /// A task representing the asynchronous test operation. [Test] public async Task WithCoreServices_RegistersObservationServices() @@ -40,17 +32,15 @@ public async Task WithCoreServices_RegistersObservationServices() RxBindingBuilder.ResetForTesting(); var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - builder.WithCoreServices(); - builder.BuildApp(); + _ = builder.WithCoreServices(); + _ = builder.BuildApp(); var services = Locator.Current.GetServices().ToList(); await Assert.That(services.Count).IsGreaterThanOrEqualTo(MinimumCoreObservableServices); } - /// - /// Verifies that WithPlatformModule registers a module. - /// + /// Verifies that WithPlatformModule registers a module. /// A task representing the asynchronous test operation. [Test] public async Task WithPlatformModule_RegistersModule() @@ -59,15 +49,13 @@ public async Task WithPlatformModule_RegistersModule() var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); var registered = false; - builder.WithPlatformModule(new TestModule(() => registered = true)); - builder.BuildApp(); + _ = builder.WithPlatformModule(new TestModule(() => registered = true)); + _ = builder.BuildApp(); await Assert.That(registered).IsTrue(); } - /// - /// Verifies that WithRegistration executes the registration action. - /// + /// Verifies that WithRegistration executes the registration action. /// A task representing the asynchronous test operation. [Test] public async Task WithRegistration_ExecutesAction() @@ -76,21 +64,19 @@ public async Task WithRegistration_ExecutesAction() var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); var executed = false; - builder.WithRegistration(_ => executed = true); + _ = builder.WithRegistration(_ => executed = true); await Assert.That(executed).IsTrue(); } - /// - /// Verifies that BuildApp sets the global ConverterService. - /// + /// Verifies that BuildApp sets the global ConverterService. /// A task representing the asynchronous test operation. [Test] public async Task BuildApp_SetsGlobalConverterService() { RxBindingBuilder.ResetForTesting(); var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - builder.WithCoreServices(); + _ = builder.WithCoreServices(); var instance = builder.BuildApp(); @@ -98,9 +84,7 @@ public async Task BuildApp_SetsGlobalConverterService() await Assert.That(BindingConverters.Current).IsNotNull(); } - /// - /// Verifies that WithCoreServices is idempotent. - /// + /// Verifies that WithCoreServices is idempotent. /// A task representing the asynchronous test operation. [Test] public async Task WithCoreServices_CalledTwice_OnlyRegistersOnce() @@ -108,18 +92,16 @@ public async Task WithCoreServices_CalledTwice_OnlyRegistersOnce() RxBindingBuilder.ResetForTesting(); var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - builder.WithCoreServices(); - builder.WithCoreServices(); - builder.BuildApp(); + _ = builder.WithCoreServices(); + _ = builder.WithCoreServices(); + _ = builder.BuildApp(); // Should not throw; services registered once var services = Locator.Current.GetServices().ToList(); await Assert.That(services.Count).IsGreaterThanOrEqualTo(MinimumCoreObservableServices); } - /// - /// Verifies that the fluent API supports chaining. - /// + /// Verifies that the fluent API supports chaining. /// A task representing the asynchronous test operation. [Test] public async Task FluentAPI_SupportsChainingCalls() @@ -127,16 +109,13 @@ public async Task FluentAPI_SupportsChainingCalls() RxBindingBuilder.ResetForTesting(); var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - builder.WithCoreServices(); - var result = builder.WithRegistration(_ => { }); + _ = builder.WithCoreServices(); + var result = builder.WithRegistration(static _ => { }); await Assert.That(result).IsNotNull(); } - /// - /// Verifies that registers a - /// typed converter that appears in the registry. - /// + /// Verifies that registers a typed converter that appears in the registry. /// A task representing the asynchronous test operation. [Test] public async Task WithConverter_RegistersInTypedConverters() @@ -146,19 +125,16 @@ public async Task WithConverter_RegistersInTypedConverters() var converter = new StubBindingTypeConverter( typeof(int), typeof(bool), - (_, _) => (true, true)); + static (_, _) => (true, true)); - builder.WithConverter(converter); + _ = builder.WithConverter(converter); var resolved = builder.ConverterService.TypedConverters.TryGetConverter(typeof(int), typeof(bool)); await Assert.That(resolved).IsNotNull(); await Assert.That(ReferenceEquals(resolved, converter)).IsTrue(); } - /// - /// Verifies that returns the builder - /// for fluent chaining. - /// + /// Verifies that returns the builder for fluent chaining. /// A task representing the asynchronous test operation. [Test] public async Task WithConverter_ReturnsSelfForChaining() @@ -168,52 +144,43 @@ public async Task WithConverter_ReturnsSelfForChaining() var converter = new StubBindingTypeConverter( typeof(int), typeof(string), - (from, _) => (true, from?.ToString())); + static (from, _) => (true, from?.ToString())); var result = builder.WithConverter(converter); await Assert.That(result).IsNotNull(); } - /// - /// Verifies that registers a - /// fallback converter that appears in the registry. - /// + /// Verifies that registers a fallback converter in . /// A task representing the asynchronous test operation. [Test] public async Task WithFallbackConverter_RegistersInFallbackConverters() { RxBindingBuilder.ResetForTesting(); var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - var converter = new StubFallbackConverter((_, _, _, _) => (true, "converted")); + var converter = new StubFallbackConverter(static (_, _, _, _) => (true, "converted")); - builder.WithFallbackConverter(converter); + _ = builder.WithFallbackConverter(converter); var allConverters = builder.ConverterService.FallbackConverters.GetAllConverters().ToList(); await Assert.That(allConverters).Contains(converter); } - /// - /// Verifies that returns the builder - /// for fluent chaining. - /// + /// Verifies that returns the builder for fluent chaining. /// A task representing the asynchronous test operation. [Test] public async Task WithFallbackConverter_ReturnsSelfForChaining() { RxBindingBuilder.ResetForTesting(); var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - var converter = new StubFallbackConverter((_, _, _, _) => (true, "converted")); + var converter = new StubFallbackConverter(static (_, _, _, _) => (true, "converted")); var result = builder.WithFallbackConverter(converter); await Assert.That(result).IsNotNull(); } - /// - /// Verifies that registers a - /// set-method converter that appears in the registry. - /// + /// Verifies that registers a set-method converter in . /// A task representing the asynchronous test operation. [Test] public async Task WithSetMethodConverter_RegistersInSetMethodConverters() @@ -222,16 +189,13 @@ public async Task WithSetMethodConverter_RegistersInSetMethodConverters() var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); var converter = new StubSetMethodBindingConverter(); - builder.WithSetMethodConverter(converter); + _ = builder.WithSetMethodConverter(converter); var allConverters = builder.ConverterService.SetMethodConverters.GetAllConverters().ToList(); await Assert.That(allConverters).Contains(converter); } - /// - /// Verifies that returns the builder - /// for fluent chaining. - /// + /// Verifies that returns the builder for fluent chaining. /// A task representing the asynchronous test operation. [Test] public async Task WithSetMethodConverter_ReturnsSelfForChaining() @@ -245,10 +209,7 @@ public async Task WithSetMethodConverter_ReturnsSelfForChaining() await Assert.That(result).IsNotNull(); } - /// - /// Verifies that registers default - /// converters, spot-checking that the is present. - /// + /// Verifies that registers default converters, spot-checking that the is present. /// A task representing the asynchronous test operation. [Test] public async Task WithCoreServices_RegistersDefaultConverters() @@ -256,17 +217,14 @@ public async Task WithCoreServices_RegistersDefaultConverters() RxBindingBuilder.ResetForTesting(); var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - builder.WithCoreServices(); + _ = builder.WithCoreServices(); // Spot-check: StringConverter registers string -> string var stringConverter = builder.ConverterService.TypedConverters.TryGetConverter(typeof(string), typeof(string)); await Assert.That(stringConverter).IsNotNull(); } - /// - /// Verifies that registers - /// the (int -> string). - /// + /// Verifies that registers the (int -> string). /// A task representing the asynchronous test operation. [Test] public async Task WithCoreServices_RegistersIntegerToStringConverter() @@ -274,66 +232,54 @@ public async Task WithCoreServices_RegistersIntegerToStringConverter() RxBindingBuilder.ResetForTesting(); var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - builder.WithCoreServices(); + _ = builder.WithCoreServices(); var converter = builder.ConverterService.TypedConverters.TryGetConverter(typeof(int), typeof(string)); await Assert.That(converter).IsNotNull(); } - /// - /// Verifies that calling - /// via the explicit interface method returns an . - /// + /// Verifies that calling via the explicit interface method returns an . /// A task representing the asynchronous test operation. [Test] public async Task WithCoreServices_ExplicitInterface_ReturnsIReactiveUIBindingBuilder() { RxBindingBuilder.ResetForTesting(); - IReactiveUIBindingBuilder iBuilder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - var result = iBuilder.WithCoreServices(); + IReactiveUIBindingBuilder builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); + var result = builder.WithCoreServices(); await Assert.That(result).IsNotNull(); } - /// - /// Verifies that sets the global - /// to the builder's . - /// + /// Verifies that sets the global to the builder's . /// A task representing the asynchronous test operation. [Test] public async Task BuildApp_SetsGlobalConverterServiceToBuilderInstance() { RxBindingBuilder.ResetForTesting(); var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - builder.WithCoreServices(); + _ = builder.WithCoreServices(); - builder.BuildApp(); + _ = builder.BuildApp(); await Assert.That(ReferenceEquals(BindingConverters.Current, builder.ConverterService)).IsTrue(); } - /// - /// Verifies that marks the system as initialized - /// so that does not throw. - /// + /// Verifies that marks the system as initialized so that does not throw. /// A task representing the asynchronous test operation. [Test] public async Task BuildApp_MarksAsInitialized() { RxBindingBuilder.ResetForTesting(); var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - builder.WithCoreServices(); + _ = builder.WithCoreServices(); - builder.BuildApp(); + _ = builder.BuildApp(); var action = RxBindingBuilder.EnsureInitialized; await Assert.That(action).ThrowsNothing(); } - /// - /// Verifies that multiple converters of different types can be registered - /// and all appear in their respective registries. - /// + /// Verifies that multiple converters of different types can be registered and all appear in their respective registries. /// A task representing the asynchronous test operation. [Test] public async Task MultipleConverterTypes_AllRegistered() @@ -343,13 +289,13 @@ public async Task MultipleConverterTypes_AllRegistered() var typed = new StubBindingTypeConverter( typeof(double), typeof(string), - (from, _) => (true, from?.ToString())); - var fallback = new StubFallbackConverter((_, _, _, _) => (true, "fallback")); + static (from, _) => (true, from?.ToString())); + var fallback = new StubFallbackConverter(static (_, _, _, _) => (true, "fallback")); var setMethod = new StubSetMethodBindingConverter(); - builder.WithConverter(typed); - builder.WithFallbackConverter(fallback); - builder.WithSetMethodConverter(setMethod); + _ = builder.WithConverter(typed); + _ = builder.WithFallbackConverter(fallback); + _ = builder.WithSetMethodConverter(setMethod); await Assert.That(builder.ConverterService.TypedConverters.TryGetConverter(typeof(double), typeof(string))) .IsNotNull(); @@ -357,10 +303,7 @@ await Assert.That(builder.ConverterService.TypedConverters.TryGetConverter(typeo await Assert.That(builder.ConverterService.SetMethodConverters.GetAllConverters().ToList()).Contains(setMethod); } - /// - /// Verifies that registers a - /// command binder that appears in Splat's services. - /// + /// Verifies that registers a command binder that appears in Splat's services. /// A task representing the asynchronous test operation. [Test] public async Task WithCommandBinder_RegistersInSplat() @@ -369,17 +312,14 @@ public async Task WithCommandBinder_RegistersInSplat() var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); var binder = new StubCommandBinder(); - builder.WithCommandBinder(binder); - builder.BuildApp(); + _ = builder.WithCommandBinder(binder); + _ = builder.BuildApp(); var services = Locator.Current.GetServices().ToList(); await Assert.That(services).Contains(binder); } - /// - /// Verifies that returns the builder - /// for fluent chaining. - /// + /// Verifies that returns the builder for fluent chaining. /// A task representing the asynchronous test operation. [Test] public async Task WithCommandBinder_ReturnsSelfForChaining() @@ -393,9 +333,7 @@ public async Task WithCommandBinder_ReturnsSelfForChaining() await Assert.That(result).IsNotNull(); } - /// - /// Verifies that throws on null binder. - /// + /// Verifies that throws on null binder. /// A task representing the asynchronous test operation. [Test] public async Task WithCommandBinder_NullBinder_Throws() @@ -407,9 +345,7 @@ await Assert.That(() => builder.WithCommandBinder(null!)) .ThrowsExactly(); } - /// - /// Verifies that ConfigureViewLocator registers a configured DefaultViewLocator. - /// + /// Verifies that ConfigureViewLocator registers a configured DefaultViewLocator. /// A task representing the asynchronous test operation. [Test] public async Task ConfigureViewLocator_RegistersConfiguredLocator() @@ -417,10 +353,10 @@ public async Task ConfigureViewLocator_RegistersConfiguredLocator() RxBindingBuilder.ResetForTesting(); var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - builder.WithCoreServices(); - builder.ConfigureViewLocator(mappings => + _ = builder.WithCoreServices(); + _ = builder.ConfigureViewLocator(static mappings => mappings.Map()); - builder.BuildApp(); + _ = builder.BuildApp(); var locator = ViewLocator.GetCurrent(); var result = locator.ResolveView(new ConfigTestViewModel()); @@ -429,9 +365,7 @@ public async Task ConfigureViewLocator_RegistersConfiguredLocator() await Assert.That(result).IsTypeOf(); } - /// - /// A test that invokes a callback when configured. - /// + /// A test that invokes a callback when configured. /// The callback to invoke during configuration. private sealed class TestModule(Action onConfigure) : Splat.Builder.IModule { @@ -439,16 +373,11 @@ private sealed class TestModule(Action onConfigure) : Splat.Builder.IModule public void Configure(IMutableDependencyResolver resolver) => onConfigure(); } - /// - /// A stub implementation of for testing registration. - /// + /// A stub implementation of for testing registration. private sealed class StubCommandBinder : ICreatesCommandBinding { /// - [SuppressMessage( - "Major Code Smell", - "S4018:Generic methods should provide type parameter for type inference", - Justification = "Type parameter is dictated by the implemented interface and is not inferable from the arguments.")] + [SuppressMessage("Design", "SST1452:Unused type parameter", Justification = "Dictated by the interface this test stub implements.")] public int GetAffinityForObject(bool hasEventTarget) => 0; /// @@ -460,11 +389,8 @@ private sealed class StubCommandBinder : ICreatesCommandBinding where T : class => null; /// + [SuppressMessage("Design", "SST1452:Unused type parameter", Justification = "Dictated by the interface this test stub implements.")] [RequiresUnreferencedCode("Test stub")] - [SuppressMessage( - "Major Code Smell", - "S4018:Generic methods should provide type parameter for type inference", - Justification = "Type parameter is dictated by the implemented interface and is not inferable from the arguments.")] public IDisposable? BindCommandToObject( System.Windows.Input.ICommand? command, T? target, @@ -483,15 +409,11 @@ private sealed class StubCommandBinder : ICreatesCommandBinding where TEventArgs : EventArgs => null; } - /// - /// Simple view model for ConfigureViewLocator testing. - /// - [SuppressMessage("Minor Code Smell", "S2094:Classes should not be empty", Justification = "Test class")] + /// Simple view model for ConfigureViewLocator testing. + [SuppressMessage("Design", "SST1436:Empty type", Justification = "The view locator tests key off the type identity alone.")] private sealed class ConfigTestViewModel; - /// - /// Simple view for ConfigureViewLocator testing. - /// + /// Simple view for ConfigureViewLocator testing. private sealed class ConfigTestView : IViewFor { /// diff --git a/src/tests/ReactiveUI.Binding.Tests/Builder/ReactiveUIBindingModuleTests.cs b/src/tests/ReactiveUI.Binding.Tests/Builder/ReactiveUIBindingModuleTests.cs index dbcca28..6c4b3ca 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Builder/ReactiveUIBindingModuleTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Builder/ReactiveUIBindingModuleTests.cs @@ -7,19 +7,13 @@ namespace ReactiveUI.Binding.Tests.Builder; -/// -/// Tests for the class. -/// +/// Tests for the class. public class ReactiveUIBindingModuleTests { - /// - /// The expected number of observable-for-property services registered by the module. - /// + /// The expected number of observable-for-property services registered by the module. private const int ExpectedObservableServices = 2; - /// - /// Verifies that Configure registers INPC and POCO observable for property implementations. - /// + /// Verifies that Configure registers INPC and POCO observable for property implementations. /// A task representing the asynchronous test operation. [Test] public async Task Configure_RegistersINPCAndPOCO() @@ -33,8 +27,8 @@ public async Task Configure_RegistersINPCAndPOCO() await Assert.That(services.Count).IsEqualTo(ExpectedObservableServices); - var hasINPC = services.Exists(s => s is INPCObservableForProperty); - var hasPOCO = services.Exists(s => s is POCOObservableForProperty); + var hasINPC = services.Exists(static s => s is INPCObservableForProperty); + var hasPOCO = services.Exists(static s => s is POCOObservableForProperty); await Assert.That(hasINPC).IsTrue(); await Assert.That(hasPOCO).IsTrue(); @@ -58,9 +52,7 @@ public async Task Configure_NoCommandBinders() await Assert.That(binders.Count).IsEqualTo(0); } - /// - /// Verifies that Configure throws for null resolver. - /// + /// Verifies that Configure throws for null resolver. /// A task representing the asynchronous test operation. [Test] public async Task Configure_NullResolver_ThrowsArgumentNullException() diff --git a/src/tests/ReactiveUI.Binding.Tests/Builder/RxBindingBuilderTests.cs b/src/tests/ReactiveUI.Binding.Tests/Builder/RxBindingBuilderTests.cs index 59d4e53..911e719 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Builder/RxBindingBuilderTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Builder/RxBindingBuilderTests.cs @@ -6,14 +6,10 @@ namespace ReactiveUI.Binding.Tests.Builder; -/// -/// Tests for the static factory class. -/// +/// Tests for the static factory class. public class RxBindingBuilderTests { - /// - /// Verifies that CreateReactiveUIBindingBuilder returns a non-null builder. - /// + /// Verifies that CreateReactiveUIBindingBuilder returns a non-null builder. /// A task representing the asynchronous test operation. [Test] public async Task CreateReactiveUIBindingBuilder_ReturnsBuilder() @@ -25,9 +21,7 @@ public async Task CreateReactiveUIBindingBuilder_ReturnsBuilder() await Assert.That(builder).IsNotNull(); } - /// - /// Verifies that EnsureInitialized throws when not initialized. - /// + /// Verifies that EnsureInitialized throws when not initialized. /// A task representing the asynchronous test operation. [Test] public async Task EnsureInitialized_NotInitialized_ThrowsInvalidOperationException() @@ -38,9 +32,7 @@ await Assert.That(RxBindingBuilder.EnsureInitialized) .ThrowsExactly(); } - /// - /// Verifies that EnsureInitialized does not throw after BuildApp has been called. - /// + /// Verifies that EnsureInitialized does not throw after BuildApp has been called. /// A task representing the asynchronous test operation. [Test] public async Task EnsureInitialized_AfterBuildApp_DoesNotThrow() @@ -48,15 +40,13 @@ public async Task EnsureInitialized_AfterBuildApp_DoesNotThrow() RxBindingBuilder.ResetForTesting(); var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - builder.WithCoreServices(); - builder.BuildApp(); + _ = builder.WithCoreServices(); + _ = builder.BuildApp(); await Assert.That(RxBindingBuilder.EnsureInitialized).ThrowsNothing(); } - /// - /// Verifies that ResetForTesting resets the initialization state. - /// + /// Verifies that ResetForTesting resets the initialization state. /// A task representing the asynchronous test operation. [Test] public async Task ResetForTesting_ResetsInitializationState() @@ -64,8 +54,8 @@ public async Task ResetForTesting_ResetsInitializationState() RxBindingBuilder.ResetForTesting(); var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - builder.WithCoreServices(); - builder.BuildApp(); + _ = builder.WithCoreServices(); + _ = builder.BuildApp(); // Should not throw RxBindingBuilder.EnsureInitialized(); @@ -89,9 +79,9 @@ public async Task WithCoreServices_CalledTwice_IsIdempotent() RxBindingBuilder.ResetForTesting(); var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - builder.WithCoreServices(); - builder.WithCoreServices(); // Second call should be a no-op - builder.BuildApp(); + _ = builder.WithCoreServices(); + _ = builder.WithCoreServices(); // Second call should be a no-op + _ = builder.BuildApp(); await Assert.That(RxBindingBuilder.EnsureInitialized).ThrowsNothing(); } @@ -112,14 +102,12 @@ public async Task CreateReactiveUIBindingBuilder_WithResolver_ReturnsBuilder() await Assert.That(builder).IsNotNull(); } - /// - /// Verifies that the extension method overload throws ArgumentNullException when resolver is null. - /// + /// Verifies that the extension method overload throws ArgumentNullException when resolver is null. /// A task representing the asynchronous test operation. [Test] public async Task CreateReactiveUIBindingBuilder_NullResolver_ThrowsArgumentNullException() { - var action = () => ((IMutableDependencyResolver)null!).CreateReactiveUIBindingBuilder(); + var action = static () => ((IMutableDependencyResolver)null!).CreateReactiveUIBindingBuilder(); await Assert.That(action).ThrowsExactly(); } @@ -155,17 +143,11 @@ private sealed class MutableOnlyResolver : IMutableDependencyResolver public bool HasRegistration(Type? serviceType, string? contract) => false; /// - [SuppressMessage( - "Major Code Smell", - "S4018:Generic methods should provide type parameter for type inference", - Justification = "Type parameter is dictated by the implemented interface and is not inferable from the arguments.")] + [SuppressMessage("Design", "SST1452:Unused type parameter", Justification = "Dictated by the interface this test stub implements.")] public bool HasRegistration() => false; /// - [SuppressMessage( - "Major Code Smell", - "S4018:Generic methods should provide type parameter for type inference", - Justification = "Type parameter is dictated by the implemented interface and is not inferable from the arguments.")] + [SuppressMessage("Design", "SST1452:Unused type parameter", Justification = "Dictated by the interface this test stub implements.")] public bool HasRegistration(string? contract) => false; /// @@ -189,10 +171,7 @@ public void Register(Func factory, string? contract) } /// - [SuppressMessage( - "Major Code Smell", - "S4018:Generic methods should provide type parameter for type inference", - Justification = "Type parameter is dictated by the implemented interface and is not inferable from the arguments.")] + [SuppressMessage("Design", "SST1452:Unused type parameter", Justification = "Dictated by the interface this test stub implements.")] public void Register() where TService : class where TImplementation : class, TService, new() @@ -200,10 +179,7 @@ public void Register() } /// - [SuppressMessage( - "Major Code Smell", - "S4018:Generic methods should provide type parameter for type inference", - Justification = "Type parameter is dictated by the implemented interface and is not inferable from the arguments.")] + [SuppressMessage("Design", "SST1452:Unused type parameter", Justification = "Dictated by the interface this test stub implements.")] public void Register(string? contract) where TService : class where TImplementation : class, TService, new() @@ -221,19 +197,13 @@ public void UnregisterCurrent(Type? serviceType, string? contract) } /// - [SuppressMessage( - "Major Code Smell", - "S4018:Generic methods should provide type parameter for type inference", - Justification = "Type parameter is dictated by the implemented interface and is not inferable from the arguments.")] + [SuppressMessage("Design", "SST1452:Unused type parameter", Justification = "Dictated by the interface this test stub implements.")] public void UnregisterCurrent() { } /// - [SuppressMessage( - "Major Code Smell", - "S4018:Generic methods should provide type parameter for type inference", - Justification = "Type parameter is dictated by the implemented interface and is not inferable from the arguments.")] + [SuppressMessage("Design", "SST1452:Unused type parameter", Justification = "Dictated by the interface this test stub implements.")] public void UnregisterCurrent(string? contract) { } @@ -249,19 +219,13 @@ public void UnregisterAll(Type? serviceType, string? contract) } /// - [SuppressMessage( - "Major Code Smell", - "S4018:Generic methods should provide type parameter for type inference", - Justification = "Type parameter is dictated by the implemented interface and is not inferable from the arguments.")] + [SuppressMessage("Design", "SST1452:Unused type parameter", Justification = "Dictated by the interface this test stub implements.")] public void UnregisterAll() { } /// - [SuppressMessage( - "Major Code Smell", - "S4018:Generic methods should provide type parameter for type inference", - Justification = "Type parameter is dictated by the implemented interface and is not inferable from the arguments.")] + [SuppressMessage("Design", "SST1452:Unused type parameter", Justification = "Dictated by the interface this test stub implements.")] public void UnregisterAll(string? contract) { } @@ -276,18 +240,12 @@ public IDisposable Disposable.Empty; /// - [SuppressMessage( - "Major Code Smell", - "S4018:Generic methods should provide type parameter for type inference", - Justification = "Type parameter is dictated by the implemented interface and is not inferable from the arguments.")] + [SuppressMessage("Design", "SST1452:Unused type parameter", Justification = "Dictated by the interface this test stub implements.")] public IDisposable ServiceRegistrationCallback(Action callback) => Disposable.Empty; /// - [SuppressMessage( - "Major Code Smell", - "S4018:Generic methods should provide type parameter for type inference", - Justification = "Type parameter is dictated by the implemented interface and is not inferable from the arguments.")] + [SuppressMessage("Design", "SST1452:Unused type parameter", Justification = "Dictated by the interface this test stub implements.")] public IDisposable ServiceRegistrationCallback(string? contract, Action callback) => Disposable.Empty; diff --git a/src/tests/ReactiveUI.Binding.Tests/CommandBinding/CommandBinderServiceTests.cs b/src/tests/ReactiveUI.Binding.Tests/CommandBinding/CommandBinderServiceTests.cs index 108dbcf..4bcf096 100644 --- a/src/tests/ReactiveUI.Binding.Tests/CommandBinding/CommandBinderServiceTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/CommandBinding/CommandBinderServiceTests.cs @@ -8,9 +8,7 @@ namespace ReactiveUI.Binding.Tests.CommandBinding; -/// -/// Tests for the class. -/// +/// Tests for the class. public class CommandBinderServiceTests { /// @@ -23,8 +21,8 @@ public async Task GetBinder_CoreServicesOnly_ReturnsNull() { RxBindingBuilder.ResetForTesting(); var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - builder.WithCoreServices(); - builder.BuildApp(); + _ = builder.WithCoreServices(); + _ = builder.BuildApp(); var binder = CommandBinderService.GetBinder(false); @@ -41,8 +39,8 @@ public async Task GetBinder_NoMatchingBinders_ReturnsNull() { RxBindingBuilder.ResetForTesting(); var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - builder.WithCoreServices(); - builder.BuildApp(); + _ = builder.WithCoreServices(); + _ = builder.BuildApp(); // PlainObject has no default events and no Command/CommandParameter properties var binder = CommandBinderService.GetBinder(false); @@ -50,20 +48,18 @@ public async Task GetBinder_NoMatchingBinders_ReturnsNull() await Assert.That(binder).IsNull(); } - /// - /// Verifies that GetBinder prefers higher affinity when custom binder is registered. - /// + /// Verifies that GetBinder prefers higher affinity when custom binder is registered. /// A task representing the asynchronous test operation. [Test] public async Task GetBinder_CustomBinder_PrefersHigherAffinity() { RxBindingBuilder.ResetForTesting(); var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - builder.WithCoreServices(); + _ = builder.WithCoreServices(); var customBinder = new HighAffinityBinder(); - builder.WithCommandBinder(customBinder); - builder.BuildApp(); + _ = builder.WithCommandBinder(customBinder); + _ = builder.BuildApp(); var binder = CommandBinderService.GetBinder(false); @@ -71,50 +67,28 @@ public async Task GetBinder_CustomBinder_PrefersHigherAffinity() await Assert.That(ReferenceEquals(binder, customBinder)).IsTrue(); } - /// - /// A mock control with a Click event for testing event-based command binder selection. - /// - [SuppressMessage("Minor Code Smell", "S2094:Classes should not be empty", Justification = "Used for testing")] - [SuppressMessage( - "Performance", - "CA1812:Avoid uninstantiated internal classes", - Justification = "Used only as a generic type argument for command-binder metadata dispatch; never constructed by design.")] + /// A mock control with a Click event for testing event-based command binder selection. private sealed class ClickableButton { #pragma warning disable CS0067 - /// - /// Occurs when the button is clicked. - /// - [SuppressMessage("Major Code Smell", "S3264:Events should be invoked", Justification = "Test model")] - public event EventHandler? Click; + /// Occurs when the button is clicked. + [SuppressMessage("Design", "SST2407:Event is never raised", Justification = "The binder only needs the event to exist; the test never raises it.")] + private event EventHandler? Click; #pragma warning restore CS0067 } - /// - /// A plain object with no events or command properties for testing null binder scenarios. - /// - [SuppressMessage("Minor Code Smell", "S2094:Classes should not be empty", Justification = "Used for testing")] - [SuppressMessage( - "Performance", - "CA1812:Avoid uninstantiated internal classes", - Justification = "Used only as a generic type argument for the null-binder dispatch path; never constructed by design.")] + /// A plain object with no events or command properties for testing null binder scenarios. + [SuppressMessage("Design", "SST1436:Empty type", Justification = "Having no members is the condition under test.")] private sealed class PlainObject; - /// - /// A custom command binder with high affinity (10) for testing binder priority selection. - /// + /// A custom command binder with high affinity (10) for testing binder priority selection. private sealed class HighAffinityBinder : ICreatesCommandBinding { - /// - /// The high affinity score reported by this binder. - /// + /// The high affinity score reported by this binder. private const int HighAffinity = 10; /// - [SuppressMessage( - "Major Code Smell", - "S4018:Generic methods should provide type parameter for type inference", - Justification = "Type parameter is dictated by the implemented interface and is not inferable from the arguments.")] + [SuppressMessage("Design", "SST1452:Unused type parameter", Justification = "Dictated by the interface this test stub implements.")] public int GetAffinityForObject(bool hasEventTarget) => HighAffinity; /// @@ -123,11 +97,8 @@ private sealed class HighAffinityBinder : ICreatesCommandBinding where T : class => null; /// + [SuppressMessage("Design", "SST1452:Unused type parameter", Justification = "Dictated by the interface this test stub implements.")] [RequiresUnreferencedCode("Test stub")] - [SuppressMessage( - "Major Code Smell", - "S4018:Generic methods should provide type parameter for type inference", - Justification = "Type parameter is dictated by the implemented interface and is not inferable from the arguments.")] public IDisposable? BindCommandToObject( ICommand? command, T? target, diff --git a/src/tests/ReactiveUI.Binding.Tests/Expression/ExpressionMixinsTests.cs b/src/tests/ReactiveUI.Binding.Tests/Expression/ExpressionMixinsTests.cs index 9b918fb..8ead64b 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Expression/ExpressionMixinsTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Expression/ExpressionMixinsTests.cs @@ -8,44 +8,22 @@ namespace ReactiveUI.Binding.Tests.Expression; -/// -/// Tests for the class. -/// +/// Tests for the class. public class ExpressionMixinsTests { - /// - /// The expected number of expressions for a two-member chain. - /// + /// The constant value embedded in the expression under test. + private const int SampleConstant = 42; + + /// The expected number of expressions for a two-member chain. private const int TwoMemberChainCount = 2; - /// - /// The expected number of expressions for a three-member chain. - /// + /// The expected number of expressions for a three-member chain. private const int ThreeMemberChainCount = 3; - /// - /// The index argument used in indexer expression tests. - /// + /// The index argument used in indexer expression tests. private const int IndexerArgument = 2; - /// - /// The first value stored in the test items list. - /// - private const int FirstItemValue = 10; - - /// - /// The second value stored in the test items list. - /// - private const int SecondItemValue = 20; - - /// - /// The third value stored in the test items list. - /// - private const int ThirdItemValue = 30; - - /// - /// Verifies that GetExpressionChain returns a single member for a simple property access. - /// + /// Verifies that GetExpressionChain returns a single member for a simple property access. /// A task representing the asynchronous test operation. [Test] public async Task GetExpressionChain_SimpleProperty_ReturnsSingleExpression() @@ -58,9 +36,7 @@ public async Task GetExpressionChain_SimpleProperty_ReturnsSingleExpression() await Assert.That(chain.Count).IsEqualTo(1); } - /// - /// Verifies that GetExpressionChain returns multiple members for a nested property chain. - /// + /// Verifies that GetExpressionChain returns multiple members for a nested property chain. /// A task representing the asynchronous test operation. [Test] public async Task GetExpressionChain_NestedProperty_ReturnsMultipleExpressions() @@ -73,9 +49,7 @@ public async Task GetExpressionChain_NestedProperty_ReturnsMultipleExpressions() await Assert.That(chain.Count).IsEqualTo(TwoMemberChainCount); } - /// - /// Verifies that GetExpressionChain returns three members for a 3-level deep property chain. - /// + /// Verifies that GetExpressionChain returns three members for a 3-level deep property chain. /// A task representing the asynchronous test operation. [Test] public async Task GetExpressionChain_ThreeLevelDeepChain_ReturnsThreeExpressions() @@ -99,9 +73,7 @@ public async Task GetExpressionChain_ThreeLevelDeepChain_ReturnsThreeExpressions await Assert.That(thirdMember!.Name).IsEqualTo("Host"); } - /// - /// Verifies that GetMemberInfo returns the correct member for a property expression. - /// + /// Verifies that GetMemberInfo returns the correct member for a property expression. /// A task representing the asynchronous test operation. [Test] public async Task GetMemberInfo_PropertyExpression_ReturnsMemberInfo() @@ -116,9 +88,7 @@ public async Task GetMemberInfo_PropertyExpression_ReturnsMemberInfo() await Assert.That(memberInfo!.Name).IsEqualTo("Name"); } - /// - /// Verifies that GetMemberInfo unwraps Convert expressions (boxing scenarios) and returns the underlying member. - /// + /// Verifies that GetMemberInfo unwraps Convert expressions (boxing scenarios) and returns the underlying member. /// A task representing the asynchronous test operation. [Test] public async Task GetMemberInfo_ConvertExpression_UnwrapsToUnderlyingMember() @@ -137,9 +107,7 @@ public async Task GetMemberInfo_ConvertExpression_UnwrapsToUnderlyingMember() await Assert.That(memberInfo.MemberType).IsEqualTo(MemberTypes.Property); } - /// - /// Verifies that GetArgumentsArray returns null for a non-index member access expression. - /// + /// Verifies that GetArgumentsArray returns null for a non-index member access expression. /// A task representing the asynchronous test operation. [Test] public async Task GetArgumentsArray_NonIndexExpression_ReturnsNull() @@ -152,9 +120,7 @@ public async Task GetArgumentsArray_NonIndexExpression_ReturnsNull() await Assert.That(args).IsNull(); } - /// - /// Verifies that GetParent returns the correct parent expression for a simple member access. - /// + /// Verifies that GetParent returns the correct parent expression for a simple member access. /// A task representing the asynchronous test operation. [Test] public async Task GetParent_MemberExpression_ReturnsParent() @@ -168,9 +134,7 @@ public async Task GetParent_MemberExpression_ReturnsParent() await Assert.That(parent!.NodeType).IsEqualTo(ExpressionType.Parameter); } - /// - /// Verifies that GetParent returns the intermediate expression for a nested member access. - /// + /// Verifies that GetParent returns the intermediate expression for a nested member access. /// A task representing the asynchronous test operation. [Test] public async Task GetParent_NestedMemberExpression_ReturnsIntermediateExpression() @@ -187,9 +151,7 @@ public async Task GetParent_NestedMemberExpression_ReturnsIntermediateExpression await Assert.That(parentMember.Member.Name).IsEqualTo("Address"); } - /// - /// Verifies that GetExpressionChain throws NotSupportedException for a ConstantExpression with a helpful message. - /// + /// Verifies that GetExpressionChain throws NotSupportedException for a ConstantExpression with a helpful message. /// A task representing the asynchronous operation. [Test] public async Task GetExpressionChain_ConstantExpression_ThrowsWithHelpfulMessage() @@ -200,31 +162,25 @@ public async Task GetExpressionChain_ConstantExpression_ThrowsWithHelpfulMessage await Assert.That(ex!.Message).Contains("Did you miss the member access prefix"); } - /// - /// Verifies that GetMemberInfo throws NotSupportedException for an unsupported expression type. - /// + /// Verifies that GetMemberInfo throws NotSupportedException for an unsupported expression type. [Test] public void GetMemberInfo_UnsupportedExpression_ThrowsNotSupportedException() { - var constant = System.Linq.Expressions.Expression.Constant(42); + var constant = System.Linq.Expressions.Expression.Constant(SampleConstant); - Assert.Throws(() => constant.GetMemberInfo()); + _ = Assert.Throws(() => constant.GetMemberInfo()); } - /// - /// Verifies that GetParent throws NotSupportedException for an unsupported expression type. - /// + /// Verifies that GetParent throws NotSupportedException for an unsupported expression type. [Test] public void GetParent_UnsupportedExpression_ThrowsNotSupportedException() { - var constant = System.Linq.Expressions.Expression.Constant(42); + var constant = System.Linq.Expressions.Expression.Constant(SampleConstant); - Assert.Throws(() => constant.GetParent()); + _ = Assert.Throws(() => constant.GetParent()); } - /// - /// Verifies that GetArgumentsArray returns constant arguments for an index expression. - /// + /// Verifies that GetArgumentsArray returns constant arguments for an index expression. /// A task representing the asynchronous test operation. [Test] public async Task GetArgumentsArray_IndexExpression_ReturnsConstantArguments() @@ -239,9 +195,7 @@ public async Task GetArgumentsArray_IndexExpression_ReturnsConstantArguments() await Assert.That(args[0]).IsEqualTo(IndexerArgument); } - /// - /// Verifies that GetExpressionChain handles index expressions in chains. - /// + /// Verifies that GetExpressionChain handles index expressions in chains. /// A task representing the asynchronous test operation. [Test] public async Task GetExpressionChain_WithIndexExpression_ReturnsChainIncludingIndex() @@ -254,9 +208,7 @@ public async Task GetExpressionChain_WithIndexExpression_ReturnsChainIncludingIn await Assert.That(chain.Count).IsEqualTo(TwoMemberChainCount); } - /// - /// Verifies that GetMemberInfo returns indexer info for an IndexExpression. - /// + /// Verifies that GetMemberInfo returns indexer info for an IndexExpression. /// A task representing the asynchronous test operation. [Test] public async Task GetMemberInfo_IndexExpression_ReturnsIndexerInfo() @@ -271,9 +223,7 @@ public async Task GetMemberInfo_IndexExpression_ReturnsIndexerInfo() await Assert.That(memberInfo!.Name).IsEqualTo("Item"); } - /// - /// Verifies that GetParent returns the object expression for an IndexExpression. - /// + /// Verifies that GetParent returns the object expression for an IndexExpression. /// A task representing the asynchronous test operation. [Test] public async Task GetParent_IndexExpression_ReturnsObjectExpression() @@ -337,38 +287,13 @@ public async Task GetExpressionChain_DirectIndexOnParameter_AddsIndexDirectly() await Assert.That(chain[0].NodeType).IsEqualTo(ExpressionType.Index); } - /// - /// Test class with a list property for testing index expression chains. - /// - [SuppressMessage( - "Performance", - "CA1812:Avoid uninstantiated internal classes", - Justification = "Referenced only inside an inspected expression tree (never compiled), so no construction is visible to the analyzer.")] - private sealed class IndexTestClass - { - /// - /// Gets a list of integers for testing index expressions. - /// - public List Items { get; } = [FirstItemValue, SecondItemValue, ThirdItemValue]; - } - - /// - /// Test class with a direct string indexer for testing index expressions on the parameter itself. - /// - [SuppressMessage( - "Performance", - "CA1812:Avoid uninstantiated internal classes", - Justification = "Referenced only via typeof/reflection metadata for its indexer; never constructed by design.")] - private sealed class DirectIndexableClass + /// Test class with a list property for testing index expression chains. + public sealed class DirectIndexableClass { - /// - /// Backing dictionary for the string indexer. - /// + /// Backing dictionary for the string indexer. private readonly Dictionary _data = new() { ["key"] = "value" }; - /// - /// Gets or sets the value associated with the specified key. - /// + /// Gets or sets the value associated with the specified key. /// The key to look up. /// The value associated with the key, or an empty string if not found. [SuppressMessage("ReSharper", "UnusedMember.Local", Justification = "Used for testing")] @@ -378,4 +303,20 @@ public string this[string key] set => _data[key] = value; } } + + /// Test class with a list property for testing index expression chains. + private sealed class IndexTestClass + { + /// The first value stored in the test items list. + private const int FirstItemValue = 10; + + /// The second value stored in the test items list. + private const int SecondItemValue = 20; + + /// The third value stored in the test items list. + private const int ThirdItemValue = 30; + + /// Gets a list of integers for testing index expressions. + public List Items { get; } = [FirstItemValue, SecondItemValue, ThirdItemValue]; + } } diff --git a/src/tests/ReactiveUI.Binding.Tests/Expression/ExpressionRewriterTests.cs b/src/tests/ReactiveUI.Binding.Tests/Expression/ExpressionRewriterTests.cs index 09c5983..1f14a5c 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Expression/ExpressionRewriterTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Expression/ExpressionRewriterTests.cs @@ -6,39 +6,37 @@ namespace ReactiveUI.Binding.Tests.Expression; -/// -/// Tests for the expression rewriter which normalizes expression trees for property path extraction. -/// +/// Tests for the expression rewriter which normalizes expression trees for property path extraction. public class ExpressionRewriterTests { - /// - /// The name of the property used across rewriter tests. - /// + /// The hint the rewriter adds when a constant is used where a member access was expected. + private const string ExpressionHintMessage = "Did you meant to use expressions"; + + /// The name of the property used in the rewriter tests. + private const string LengthPropertyName = "Length"; + + /// The right-hand operand of the comparison in the expression under test. + private const int ComparisonThreshold = 5; + + /// The constant value embedded in the expression under test. + private const int SampleConstant = 42; + + /// The name of the property used across rewriter tests. private const string PropertyName = "Property"; - /// - /// The expected number of rewritten arguments in the argument-list test. - /// + /// The expected number of rewritten arguments in the argument-list test. private const int ExpectedArgumentCount = 3; - /// - /// The index of the third rewritten argument. - /// + /// The index of the third rewritten argument. private const int ThirdArgumentIndex = 2; - /// - /// The second constant value used in the argument-list test. - /// + /// The second constant value used in the argument-list test. private const int SecondConstant = 2; - /// - /// The third constant value used in the argument-list test. - /// + /// The third constant value used in the argument-list test. private const int ThirdConstant = 3; - /// - /// Verifies that array index expressions are rewritten to index expressions. - /// + /// Verifies that array index expressions are rewritten to index expressions. /// A task representing the asynchronous operation. [Test] public async Task Rewrite_WithArrayIndex_ReturnsIndexExpression() @@ -50,9 +48,7 @@ public async Task Rewrite_WithArrayIndex_ReturnsIndexExpression() await Assert.That(result.NodeType).IsEqualTo(ExpressionType.Index); } - /// - /// Verifies that array index with non-constant index throws. - /// + /// Verifies that array index with non-constant index throws. /// A non-constant index, supplied as a parameter so it is captured as a /// non-constant closure reference (a const or literal would be inlined into the tree). [Test] @@ -61,12 +57,10 @@ public void Rewrite_WithArrayIndexNonConstant_Throws(int index) { Expression> expr = x => x.Array[index]; - Assert.Throws(() => Reflection.Rewrite(expr.Body)); + _ = Assert.Throws(() => Reflection.Rewrite(expr.Body)); } - /// - /// Verifies that array length is rewritten to member access. - /// + /// Verifies that array length is rewritten to member access. /// A task representing the asynchronous operation. [Test] public async Task Rewrite_WithArrayLength_ReturnsMemberAccess() @@ -78,12 +72,10 @@ public async Task Rewrite_WithArrayLength_ReturnsMemberAccess() // ArrayLength should be rewritten to MemberAccess of Length property await Assert.That(result.NodeType).IsEqualTo(ExpressionType.MemberAccess); var memberExpr = (MemberExpression)result; - await Assert.That(memberExpr.Member.Name).IsEqualTo("Length"); + await Assert.That(memberExpr.Member.Name).IsEqualTo(LengthPropertyName); } - /// - /// Verifies that constant expressions pass through unchanged. - /// + /// Verifies that constant expressions pass through unchanged. /// A task representing the asynchronous operation. [Test] public async Task Rewrite_WithConstant_ReturnsConstantExpression() @@ -95,9 +87,7 @@ public async Task Rewrite_WithConstant_ReturnsConstantExpression() await Assert.That(result.NodeType).IsEqualTo(ExpressionType.Constant); } - /// - /// Verifies that convert expressions are unwrapped. - /// + /// Verifies that convert expressions are unwrapped. /// A task representing the asynchronous operation. [Test] public async Task Rewrite_WithConvert_ReturnsUnderlyingExpression() @@ -110,9 +100,7 @@ public async Task Rewrite_WithConvert_ReturnsUnderlyingExpression() await Assert.That(result.NodeType).IsEqualTo(ExpressionType.MemberAccess); } - /// - /// Verifies that index expression with constant arguments are validated. - /// + /// Verifies that index expression with constant arguments are validated. /// A task representing the asynchronous operation. [Test] public async Task Rewrite_WithIndexExpression_ValidatesConstantArguments() @@ -124,9 +112,7 @@ public async Task Rewrite_WithIndexExpression_ValidatesConstantArguments() await Assert.That(result.NodeType).IsEqualTo(ExpressionType.Index); } - /// - /// Verifies that index expression with non-constant arguments throws. - /// + /// Verifies that index expression with non-constant arguments throws. [Test] public void Rewrite_WithIndexExpressionNonConstantArguments_Throws() { @@ -137,12 +123,10 @@ public void Rewrite_WithIndexExpressionNonConstantArguments_Throws() var nonConstantArg = System.Linq.Expressions.Expression.Parameter(typeof(int), "index"); var indexExpr = System.Linq.Expressions.Expression.MakeIndex(listProperty, indexer, [nonConstantArg]); - Assert.Throws(() => Reflection.Rewrite(indexExpr)); + _ = Assert.Throws(() => Reflection.Rewrite(indexExpr)); } - /// - /// Verifies that list indexer expressions are rewritten to index expressions. - /// + /// Verifies that list indexer expressions are rewritten to index expressions. /// A task representing the asynchronous operation. [Test] public async Task Rewrite_WithListIndexer_ReturnsIndexExpression() @@ -154,9 +138,7 @@ public async Task Rewrite_WithListIndexer_ReturnsIndexExpression() await Assert.That(result.NodeType).IsEqualTo(ExpressionType.Index); } - /// - /// Verifies that list indexer with non-constant index throws. - /// + /// Verifies that list indexer with non-constant index throws. /// A non-constant index, supplied as a parameter so it is captured as a /// non-constant closure reference (a const or literal would be inlined into the tree). [Test] @@ -165,12 +147,10 @@ public void Rewrite_WithListIndexerNonConstant_Throws(int index) { Expression> expr = x => x.List[index]; - Assert.Throws(() => Reflection.Rewrite(expr.Body)); + _ = Assert.Throws(() => Reflection.Rewrite(expr.Body)); } - /// - /// Verifies that member access expressions pass through unchanged. - /// + /// Verifies that member access expressions pass through unchanged. /// A task representing the asynchronous operation. [Test] public async Task Rewrite_WithMemberAccess_ReturnsMemberExpression() @@ -182,20 +162,16 @@ public async Task Rewrite_WithMemberAccess_ReturnsMemberExpression() await Assert.That(result.NodeType).IsEqualTo(ExpressionType.MemberAccess); } - /// - /// Verifies that non-special method calls throw. - /// + /// Verifies that non-special method calls throw. [Test] public void Rewrite_WithMethodCallNonSpecialName_Throws() { Expression> expr = x => x.GetValue(); - Assert.Throws(() => Reflection.Rewrite(expr.Body)); + _ = Assert.Throws(() => Reflection.Rewrite(expr.Body)); } - /// - /// Verifies that nested member access expressions pass through unchanged. - /// + /// Verifies that nested member access expressions pass through unchanged. /// A task representing the asynchronous operation. [Test] public async Task Rewrite_WithNestedMemberAccess_ReturnsMemberExpression() @@ -207,16 +183,12 @@ public async Task Rewrite_WithNestedMemberAccess_ReturnsMemberExpression() await Assert.That(result.NodeType).IsEqualTo(ExpressionType.MemberAccess); } - /// - /// Verifies that null expression throws. - /// + /// Verifies that null expression throws. [Test] public void Rewrite_WithNullExpression_Throws() => - Assert.Throws(() => Reflection.Rewrite(null)); + Assert.Throws(static () => Reflection.Rewrite(null)); - /// - /// Verifies that parameter expressions pass through unchanged. - /// + /// Verifies that parameter expressions pass through unchanged. /// A task representing the asynchronous operation. [Test] public async Task Rewrite_WithParameterExpression_ReturnsParameterExpression() @@ -228,9 +200,7 @@ public async Task Rewrite_WithParameterExpression_ReturnsParameterExpression() await Assert.That(result.NodeType).IsEqualTo(ExpressionType.Parameter); } - /// - /// Verifies that unsupported unary expressions throw. - /// + /// Verifies that unsupported unary expressions throw. [Test] public void Rewrite_WithUnaryExpressionNotArrayLengthOrConvert_Throws() { @@ -239,25 +209,21 @@ public void Rewrite_WithUnaryExpressionNotArrayLengthOrConvert_Throws() var parameter = System.Linq.Expressions.Expression.Parameter(typeof(bool), "x"); var notExpr = System.Linq.Expressions.Expression.Not(parameter); - Assert.Throws(() => Reflection.Rewrite(notExpr)); + _ = Assert.Throws(() => Reflection.Rewrite(notExpr)); } - /// - /// Verifies that unsupported binary expressions throw with helpful message. - /// + /// Verifies that unsupported binary expressions throw with helpful message. /// A task representing the asynchronous operation. [Test] public async Task Rewrite_WithUnsupportedBinaryExpression_ThrowsWithHelpfulMessage() { - Expression> expr = x => x > 5; + Expression> expr = x => x > ComparisonThreshold; var ex = Assert.Throws(() => Reflection.Rewrite(expr.Body)); - await Assert.That(ex!.Message).Contains("Did you meant to use expressions"); + await Assert.That(ex!.Message).Contains(ExpressionHintMessage); } - /// - /// Verifies that unsupported expressions throw with node type in message. - /// + /// Verifies that unsupported expressions throw with node type in message. /// A task representing the asynchronous operation. [Test] public async Task Rewrite_WithUnsupportedExpression_Throws() @@ -269,9 +235,7 @@ public async Task Rewrite_WithUnsupportedExpression_Throws() await Assert.That(ex.Message).Contains("Add"); } - /// - /// Verifies that Convert expression wrapping a member access is unwrapped to the inner member access. - /// + /// Verifies that Convert expression wrapping a member access is unwrapped to the inner member access. /// A task representing the asynchronous operation. [Test] public async Task Rewrite_WithConvertWrappingMemberAccess_UnwrapsToMemberAccess() @@ -287,9 +251,7 @@ public async Task Rewrite_WithConvertWrappingMemberAccess_UnwrapsToMemberAccess( await Assert.That(memberExpr.Member.Name).IsEqualTo(PropertyName); } - /// - /// Verifies that a static method call (non-special-name) throws NotSupportedException. - /// + /// Verifies that a static method call (non-special-name) throws NotSupportedException. /// A task representing the asynchronous operation. [Test] public async Task Rewrite_WithStaticMethodCall_ThrowsNotSupportedException() @@ -310,7 +272,7 @@ public async Task Rewrite_WithStaticMethodCall_ThrowsNotSupportedException() [Test] public async Task GetItemProperty_TypeWithoutIndexer_ThrowsInvalidOperationException() { - var action = () => ExpressionRewriter.GetItemProperty(typeof(string)); + var action = static () => ExpressionRewriter.GetItemProperty(typeof(string)); await Assert.That(action).ThrowsExactly(); } @@ -323,7 +285,7 @@ public async Task GetItemProperty_TypeWithoutIndexer_ThrowsInvalidOperationExcep [Test] public async Task GetLengthProperty_TypeWithoutLength_ThrowsInvalidOperationException() { - var action = () => ExpressionRewriter.GetLengthProperty(typeof(int)); + var action = static () => ExpressionRewriter.GetLengthProperty(typeof(int)); await Assert.That(action).ThrowsExactly(); } @@ -365,7 +327,7 @@ public async Task Rewrite_ArrayLength_ProducesMemberAccessOnLength() await Assert.That(result.NodeType).IsEqualTo(ExpressionType.MemberAccess); var memberExpr = (MemberExpression)result; - await Assert.That(memberExpr.Member.Name).IsEqualTo("Length"); + await Assert.That(memberExpr.Member.Name).IsEqualTo(LengthPropertyName); await Assert.That(memberExpr.Expression!.Type).IsEqualTo(typeof(int[])); } @@ -397,16 +359,14 @@ public async Task Rewrite_IndexExpressionWithNonConstantArguments_ThrowsNotSuppo public async Task AllConstant_EmptyCollection_ReturnsTrue() { var emptyList = new System.Collections.ObjectModel.ReadOnlyCollection( - Array.Empty()); + []); var result = ExpressionRewriter.AllConstant(emptyList); await Assert.That(result).IsTrue(); } - /// - /// Verifies that AllConstant returns false when a non-constant expression is present. - /// + /// Verifies that AllConstant returns false when a non-constant expression is present. /// A task representing the asynchronous test operation. [Test] public async Task AllConstant_WithNonConstant_ReturnsFalse() @@ -422,9 +382,7 @@ public async Task AllConstant_WithNonConstant_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies that AllConstant returns true when all expressions are constants. - /// + /// Verifies that AllConstant returns true when all expressions are constants. /// A task representing the asynchronous test operation. [Test] public async Task AllConstant_WithAllConstants_ReturnsTrue() @@ -432,7 +390,7 @@ public async Task AllConstant_WithAllConstants_ReturnsTrue() var list = new System.Collections.ObjectModel.ReadOnlyCollection( [ System.Linq.Expressions.Expression.Constant(1), - System.Linq.Expressions.Expression.Constant(2) + System.Linq.Expressions.Expression.Constant(SecondConstant) ]); var result = ExpressionRewriter.AllConstant(list); @@ -450,7 +408,7 @@ public async Task VisitArgumentList_EmptyArguments_ReturnsEmptyArray() { var rewriter = new ExpressionRewriter(); var emptyArgs = new System.Collections.ObjectModel.ReadOnlyCollection( - Array.Empty()); + []); var result = rewriter.VisitArgumentList(emptyArgs); @@ -491,13 +449,13 @@ public async Task VisitArgumentList_WithConstantArguments_VisitsEach() [Test] public async Task CreateUnsupportedNodeException_NonBinaryExpression_DoesNotContainBinaryHint() { - var constant = System.Linq.Expressions.Expression.Constant(42); + var constant = System.Linq.Expressions.Expression.Constant(SampleConstant); var exception = ExpressionRewriter.CreateUnsupportedNodeException(constant); await Assert.That(exception).IsNotNull(); await Assert.That(exception.Message).Contains("Unsupported expression of type 'Constant'"); - await Assert.That(exception.Message).DoesNotContain("Did you meant to use expressions"); + await Assert.That(exception.Message).DoesNotContain(ExpressionHintMessage); } /// @@ -509,13 +467,13 @@ public async Task CreateUnsupportedNodeException_NonBinaryExpression_DoesNotCont public async Task CreateUnsupportedNodeException_BinaryExpression_ContainsBinaryHint() { var left = System.Linq.Expressions.Expression.Constant(1); - var right = System.Linq.Expressions.Expression.Constant(2); + var right = System.Linq.Expressions.Expression.Constant(SecondConstant); var binary = System.Linq.Expressions.Expression.Add(left, right); var exception = ExpressionRewriter.CreateUnsupportedNodeException(binary); await Assert.That(exception).IsNotNull(); - await Assert.That(exception.Message).Contains("Did you meant to use expressions"); + await Assert.That(exception.Message).Contains(ExpressionHintMessage); await Assert.That(exception.Message).Contains("1"); await Assert.That(exception.Message).Contains("2"); } @@ -628,74 +586,40 @@ public async Task GetLengthProperty_TypeWithLength_ReturnsProperty() var property = ExpressionRewriter.GetLengthProperty(typeof(int[])); await Assert.That(property).IsNotNull(); - await Assert.That(property.Name).IsEqualTo("Length"); + await Assert.That(property.Name).IsEqualTo(LengthPropertyName); } - /// - /// Test class used as a type parameter in expression lambdas for rewriter tests. - /// - [SuppressMessage( - "Performance", - "CA1812:Avoid uninstantiated internal classes", - Justification = "Referenced only inside inspected expression-lambda trees (never compiled), so no construction is visible to the analyzer.")] + /// Test class used as a type parameter in expression lambdas for rewriter tests. private sealed class TestClass { - /// - /// The second sample value stored in . - /// + /// The second sample value stored in . private const int ArraySecondValue = 2; - /// - /// The third sample value stored in . - /// + /// The third sample value stored in . private const int ArrayThirdValue = 3; - /// - /// The first sample value stored in . - /// + /// The first sample value stored in . private const int ListFirstValue = 4; - /// - /// The second sample value stored in . - /// + /// The second sample value stored in . private const int ListSecondValue = 5; - /// - /// The third sample value stored in . - /// + /// The third sample value stored in . private const int ListThirdValue = 6; - /// - /// Gets an integer array for testing array index and length expressions. - /// + /// Gets an integer array for testing array index and length expressions. public int[] Array { get; } = [1, ArraySecondValue, ArrayThirdValue]; - /// - /// Gets a list of integers for testing list indexer expressions. - /// + /// Gets a list of integers for testing list indexer expressions. public List List { get; } = [ListFirstValue, ListSecondValue, ListThirdValue]; - /// - /// Gets or sets a nested instance for testing nested member access expressions. - /// - [SuppressMessage( - "Major Code Smell", - "S3459:Unassigned members should be removed", - Justification = "Referenced only as expression-tree metadata in rewriter tests; never assigned at runtime.")] + /// Gets or sets a nested instance for testing nested member access expressions. public TestClass? Nested { get; set; } - /// - /// Gets or sets a string property for testing simple member access expressions. - /// - [SuppressMessage( - "Major Code Smell", - "S3459:Unassigned members should be removed", - Justification = "Referenced only via expression-tree lambdas (and GetValue) in rewriter tests; never assigned at runtime.")] + /// Gets or sets a string property for testing simple member access expressions. public string? Property { get; set; } - /// - /// Gets the value of . Used to test non-special-name method call rewriting. - /// + /// Gets the value of . Used to test non-special-name method call rewriting. /// The current value of the . public string? GetValue() => Property; } diff --git a/src/tests/ReactiveUI.Binding.Tests/Expression/ReflectionTests.cs b/src/tests/ReactiveUI.Binding.Tests/Expression/ReflectionTests.cs index 41aa144..c9729c5 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Expression/ReflectionTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Expression/ReflectionTests.cs @@ -2,44 +2,43 @@ // ReactiveUI Association Incorporated licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System.Reflection; using ReactiveUI.Binding.Expressions; using ReactiveUI.Binding.Tests.TestModels; namespace ReactiveUI.Binding.Tests.Expression; -/// -/// Tests for the class. -/// +/// Tests for the class. public class ReflectionTests { - /// - /// A sample name value used across reflection tests. - /// + /// The name of the public field the reflection tests resolve. + private const string PublicFieldName = "PublicField"; + + /// The first argument of the two-dimensional indexer under test. + private const int FirstIndexArgument = 3; + + /// A sample value used by these tests. + private const int SampleValue = 42; + + /// The second argument of the two-dimensional indexer under test. + private const int SecondIndexArgument = 5; + + /// A sample name value used across reflection tests. private const string SampleName = "Alice"; - /// - /// The name of a method member used to exercise non-property reflection paths. - /// + /// The name of a method member used to exercise non-property reflection paths. private const string HashCodeMethodName = "GetHashCode"; - /// - /// A replacement value assigned through a reflection-based setter. - /// + /// A replacement value assigned through a reflection-based setter. private const string NewFieldValue = "NewValue"; - /// - /// The expected number of values returned for a two-element property chain. - /// + /// The expected number of values returned for a two-element property chain. private const int ExpectedTwoValues = 2; - /// - /// The index of the third value in a property chain result. - /// + /// The index of the third value in a property chain result. private const int ThirdValueIndex = 2; - /// - /// Verifies that ExpressionToPropertyNames returns the correct name for a simple property. - /// + /// Verifies that ExpressionToPropertyNames returns the correct name for a simple property. /// A task representing the asynchronous test operation. [Test] public async Task ExpressionToPropertyNames_SimpleProperty_ReturnsName() @@ -52,9 +51,7 @@ public async Task ExpressionToPropertyNames_SimpleProperty_ReturnsName() await Assert.That(name).IsEqualTo("Name"); } - /// - /// Verifies that ExpressionToPropertyNames returns a dotted path for nested properties. - /// + /// Verifies that ExpressionToPropertyNames returns a dotted path for nested properties. /// A task representing the asynchronous test operation. [Test] public async Task ExpressionToPropertyNames_NestedProperty_ReturnsDottedPath() @@ -67,9 +64,7 @@ public async Task ExpressionToPropertyNames_NestedProperty_ReturnsDottedPath() await Assert.That(name).IsEqualTo("Address.City"); } - /// - /// Verifies that GetValueFetcherOrThrow returns a working getter for a property. - /// + /// Verifies that GetValueFetcherOrThrow returns a working getter for a property. /// A task representing the asynchronous test operation. [Test] public async Task GetValueFetcherOrThrow_PropertyMember_ReturnsGetter() @@ -83,9 +78,7 @@ public async Task GetValueFetcherOrThrow_PropertyMember_ReturnsGetter() await Assert.That(value).IsEqualTo("Test"); } - /// - /// Verifies that GetValueSetterOrThrow returns a working setter for a property. - /// + /// Verifies that GetValueSetterOrThrow returns a working setter for a property. /// A task representing the asynchronous test operation. [Test] public async Task GetValueSetterOrThrow_PropertyMember_ReturnsSetter() @@ -99,9 +92,7 @@ public async Task GetValueSetterOrThrow_PropertyMember_ReturnsSetter() await Assert.That(vm.Name).IsEqualTo("Hello"); } - /// - /// Verifies that TryGetValueForPropertyChain returns the correct value for a simple chain. - /// + /// Verifies that TryGetValueForPropertyChain returns the correct value for a simple chain. /// A task representing the asynchronous test operation. [Test] public async Task TryGetValueForPropertyChain_SimpleProperty_ReturnsValue() @@ -117,9 +108,7 @@ public async Task TryGetValueForPropertyChain_SimpleProperty_ReturnsValue() await Assert.That(value).IsEqualTo(SampleName); } - /// - /// Verifies that TryGetValueForPropertyChain traverses nested properties. - /// + /// Verifies that TryGetValueForPropertyChain traverses nested properties. /// A task representing the asynchronous test operation. [Test] public async Task TryGetValueForPropertyChain_NestedProperty_TraversesChain() @@ -135,9 +124,7 @@ public async Task TryGetValueForPropertyChain_NestedProperty_TraversesChain() await Assert.That(value).IsEqualTo("Seattle"); } - /// - /// Verifies that TryGetValueForPropertyChain returns false when a null is in the chain. - /// + /// Verifies that TryGetValueForPropertyChain returns false when a null is in the chain. /// A task representing the asynchronous test operation. [Test] public async Task TryGetValueForPropertyChain_NullInChain_ReturnsFalse() @@ -152,9 +139,7 @@ public async Task TryGetValueForPropertyChain_NullInChain_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies that TrySetValueToPropertyChain sets a value on a simple property. - /// + /// Verifies that TrySetValueToPropertyChain sets a value on a simple property. /// A task representing the asynchronous test operation. [Test] public async Task TrySetValueToPropertyChain_SimpleProperty_SetsValue() @@ -170,9 +155,7 @@ public async Task TrySetValueToPropertyChain_SimpleProperty_SetsValue() await Assert.That(vm.Name).IsEqualTo("Bob"); } - /// - /// Verifies that TryGetAllValuesForPropertyChain returns intermediate ObservedChange objects for a simple property. - /// + /// Verifies that TryGetAllValuesForPropertyChain returns intermediate ObservedChange objects for a simple property. /// A task representing the asynchronous test operation. [Test] public async Task TryGetAllValuesForPropertyChain_SimpleProperty_ReturnsObservedChanges() @@ -191,9 +174,7 @@ public async Task TryGetAllValuesForPropertyChain_SimpleProperty_ReturnsObserved await Assert.That(changeValues[0].Value).IsEqualTo(SampleName); } - /// - /// Verifies that TryGetAllValuesForPropertyChain returns multiple ObservedChange objects for a deep chain. - /// + /// Verifies that TryGetAllValuesForPropertyChain returns multiple ObservedChange objects for a deep chain. /// A task representing the asynchronous test operation. [Test] public async Task TryGetAllValuesForPropertyChain_DeepChain_ReturnsMultipleValues() @@ -216,9 +197,7 @@ public async Task TryGetAllValuesForPropertyChain_DeepChain_ReturnsMultipleValue await Assert.That(changeValues[1].Value).IsEqualTo("Portland"); } - /// - /// Verifies that TrySetValueToPropertyChain sets a value through a deep property chain. - /// + /// Verifies that TrySetValueToPropertyChain sets a value through a deep property chain. /// A task representing the asynchronous test operation. [Test] public async Task TrySetValueToPropertyChain_DeepChain_SetsValue() @@ -235,9 +214,7 @@ public async Task TrySetValueToPropertyChain_DeepChain_SetsValue() await Assert.That(address.City).IsEqualTo("New"); } - /// - /// Verifies that TrySetValueToPropertyChain returns false when a null intermediate is in the chain. - /// + /// Verifies that TrySetValueToPropertyChain returns false when a null intermediate is in the chain. /// A task representing the asynchronous test operation. [Test] public async Task TrySetValueToPropertyChain_NullIntermediate_ReturnsFalse() @@ -288,9 +265,7 @@ public async Task ExpressionToPropertyNames_DeeperChain_ReturnsDottedPath() await Assert.That(name).IsEqualTo("Chain2.Chain3.Host.SomeOtherParam"); } - /// - /// Verifies that GetValueFetcherForProperty returns null for a member that is neither a field nor a property. - /// + /// Verifies that GetValueFetcherForProperty returns null for a member that is neither a field nor a property. /// A task representing the asynchronous test operation. [Test] public async Task GetValueFetcherForProperty_MethodMember_ReturnsNull() @@ -301,14 +276,12 @@ public async Task GetValueFetcherForProperty_MethodMember_ReturnsNull() await Assert.That(fetcher).IsNull(); } - /// - /// Verifies that GetValueFetcherForProperty returns a working getter for a field member. - /// + /// Verifies that GetValueFetcherForProperty returns a working getter for a field member. /// A task representing the asynchronous test operation. [Test] public async Task GetValueFetcherForProperty_FieldMember_ReturnsGetter() { - var fieldInfo = typeof(FieldTestModel).GetField("PublicField")!; + var fieldInfo = typeof(FieldTestModel).GetField(PublicFieldName)!; var getter = Reflection.GetValueFetcherForProperty(fieldInfo); await Assert.That(getter).IsNotNull(); @@ -319,14 +292,12 @@ public async Task GetValueFetcherForProperty_FieldMember_ReturnsGetter() await Assert.That(value).IsEqualTo("FieldValue"); } - /// - /// Verifies that GetValueSetterForProperty returns a working setter for a field member. - /// + /// Verifies that GetValueSetterForProperty returns a working setter for a field member. /// A task representing the asynchronous test operation. [Test] public async Task GetValueSetterForProperty_FieldMember_ReturnsSetter() { - var fieldInfo = typeof(FieldTestModel).GetField("PublicField")!; + var fieldInfo = typeof(FieldTestModel).GetField(PublicFieldName)!; var setter = Reflection.GetValueSetterForProperty(fieldInfo); await Assert.That(setter).IsNotNull(); @@ -337,9 +308,7 @@ public async Task GetValueSetterForProperty_FieldMember_ReturnsSetter() await Assert.That(model.PublicField).IsEqualTo(NewFieldValue); } - /// - /// Verifies that GetValueSetterForProperty returns null for a method member. - /// + /// Verifies that GetValueSetterForProperty returns null for a method member. /// A task representing the asynchronous test operation. [Test] public async Task GetValueSetterForProperty_MethodMember_ReturnsNull() @@ -350,31 +319,25 @@ public async Task GetValueSetterForProperty_MethodMember_ReturnsNull() await Assert.That(setter).IsNull(); } - /// - /// Verifies that GetValueFetcherOrThrow throws for a method member. - /// + /// Verifies that GetValueFetcherOrThrow throws for a method member. [Test] public void GetValueFetcherOrThrow_MethodMember_ThrowsArgumentException() { var methodInfo = typeof(TestViewModel).GetMethod(HashCodeMethodName)!; - Assert.Throws(() => Reflection.GetValueFetcherOrThrow(methodInfo)); + _ = Assert.Throws(() => Reflection.GetValueFetcherOrThrow(methodInfo)); } - /// - /// Verifies that GetValueSetterOrThrow throws for a method member. - /// + /// Verifies that GetValueSetterOrThrow throws for a method member. [Test] public void GetValueSetterOrThrow_MethodMember_ThrowsArgumentException() { var methodInfo = typeof(TestViewModel).GetMethod(HashCodeMethodName)!; - Assert.Throws(() => Reflection.GetValueSetterOrThrow(methodInfo)); + _ = Assert.Throws(() => Reflection.GetValueSetterOrThrow(methodInfo)); } - /// - /// Verifies that TryGetAllValuesForPropertyChain returns false when null is in the chain. - /// + /// Verifies that TryGetAllValuesForPropertyChain returns false when null is in the chain. /// A task representing the asynchronous test operation. [Test] public async Task TryGetAllValuesForPropertyChain_NullInChain_ReturnsFalse() @@ -389,9 +352,7 @@ public async Task TryGetAllValuesForPropertyChain_NullInChain_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies that ExpressionToPropertyNames handles index expression paths. - /// + /// Verifies that ExpressionToPropertyNames handles index expression paths. /// A task representing the asynchronous test operation. [Test] public async Task ExpressionToPropertyNames_IndexExpression_ReturnsPathWithIndex() @@ -405,9 +366,7 @@ public async Task ExpressionToPropertyNames_IndexExpression_ReturnsPathWithIndex await Assert.That(name).Contains("[0]"); } - /// - /// Verifies that GetValueSetterForProperty returns a working setter for a property member. - /// + /// Verifies that GetValueSetterForProperty returns a working setter for a property member. /// A task representing the asynchronous test operation. [Test] public async Task GetValueSetterForProperty_PropertyMember_ReturnsSetter() @@ -423,9 +382,7 @@ public async Task GetValueSetterForProperty_PropertyMember_ReturnsSetter() await Assert.That(vm.Name).IsEqualTo("Test"); } - /// - /// Verifies that MaterializeExpressions returns the same array when given an array. - /// + /// Verifies that MaterializeExpressions returns the same array when given an array. /// A task representing the asynchronous test operation. [Test] public async Task MaterializeExpressions_ArrayInput_ReturnsSameArray() @@ -440,9 +397,7 @@ public async Task MaterializeExpressions_ArrayInput_ReturnsSameArray() await Assert.That(ReferenceEquals(result, array)).IsTrue(); } - /// - /// Verifies that MaterializeExpressions returns empty array for an empty ICollection. - /// + /// Verifies that MaterializeExpressions returns empty array for an empty ICollection. /// A task representing the asynchronous test operation. [Test] public async Task MaterializeExpressions_EmptyCollection_ReturnsEmptyArray() @@ -454,9 +409,7 @@ public async Task MaterializeExpressions_EmptyCollection_ReturnsEmptyArray() await Assert.That(result.Length).IsEqualTo(0); } - /// - /// Verifies that MaterializeExpressions copies from a non-empty ICollection. - /// + /// Verifies that MaterializeExpressions copies from a non-empty ICollection. /// A task representing the asynchronous test operation. [Test] public async Task MaterializeExpressions_NonEmptyCollection_CopiesElements() @@ -471,9 +424,7 @@ public async Task MaterializeExpressions_NonEmptyCollection_CopiesElements() await Assert.That(result.Length).IsEqualTo(list.Count); } - /// - /// Verifies that MaterializeExpressions handles a general IEnumerable (not array or ICollection). - /// + /// Verifies that MaterializeExpressions handles a general IEnumerable (not array or ICollection). /// A task representing the asynchronous test operation. [Test] public async Task MaterializeExpressions_GeneralEnumerable_MaterializesToArray() @@ -518,14 +469,12 @@ public async Task TrySetValueToPropertyChain_ShouldThrowTrue_NullFinalParent_Ret await Assert.That(result).IsFalse(); } - /// - /// Verifies that GetValueFetcherForProperty for a field throws when the field value is null. - /// + /// Verifies that GetValueFetcherForProperty for a field throws when the field value is null. /// A task representing the asynchronous test operation. [Test] public async Task GetValueFetcherForProperty_FieldMember_NullValue_Throws() { - var fieldInfo = typeof(FieldTestModel).GetField("PublicField")!; + var fieldInfo = typeof(FieldTestModel).GetField(PublicFieldName)!; var getter = Reflection.GetValueFetcherForProperty(fieldInfo); await Assert.That(getter).IsNotNull(); @@ -536,45 +485,37 @@ public async Task GetValueFetcherForProperty_FieldMember_NullValue_Throws() await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that TryGetValueForPropertyChain throws for empty expression chain. - /// + /// Verifies that TryGetValueForPropertyChain throws for empty expression chain. /// A task representing the asynchronous test operation. [Test] public async Task TryGetValueForPropertyChain_EmptyChain_ThrowsInvalidOperationException() { - var act = () => Reflection.TryGetValueForPropertyChain(out _, new TestViewModel(), []); + var act = static () => Reflection.TryGetValueForPropertyChain(out _, new TestViewModel(), []); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that TryGetAllValuesForPropertyChain throws for empty expression chain. - /// + /// Verifies that TryGetAllValuesForPropertyChain throws for empty expression chain. /// A task representing the asynchronous test operation. [Test] public async Task TryGetAllValuesForPropertyChain_EmptyChain_ThrowsInvalidOperationException() { - var act = () => Reflection.TryGetAllValuesForPropertyChain(out _, new TestViewModel(), []); + var act = static () => Reflection.TryGetAllValuesForPropertyChain(out _, new TestViewModel(), []); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that TrySetValueToPropertyChain throws for empty expression chain. - /// + /// Verifies that TrySetValueToPropertyChain throws for empty expression chain. /// A task representing the asynchronous test operation. [Test] public async Task TrySetValueToPropertyChain_EmptyChain_ThrowsInvalidOperationException() { - var act = () => Reflection.TrySetValueToPropertyChain(new TestViewModel(), [], "value"); + var act = static () => Reflection.TrySetValueToPropertyChain(new TestViewModel(), [], "value"); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that TryGetValueForPropertyChain returns false when the root object is null. - /// + /// Verifies that TryGetValueForPropertyChain returns false when the root object is null. /// A task representing the asynchronous test operation. [Test] public async Task TryGetValueForPropertyChain_NullRoot_ReturnsFalse() @@ -589,9 +530,7 @@ public async Task TryGetValueForPropertyChain_NullRoot_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies that TryGetAllValuesForPropertyChain returns false when the last object in chain is null. - /// + /// Verifies that TryGetAllValuesForPropertyChain returns false when the last object in chain is null. /// A task representing the asynchronous test operation. [Test] public async Task TryGetAllValuesForPropertyChain_NullAtLastStep_ReturnsFalse() @@ -606,9 +545,7 @@ public async Task TryGetAllValuesForPropertyChain_NullAtLastStep_ReturnsFalse() await Assert.That(result).IsFalse(); } - /// - /// Verifies that TrySetValueToPropertyChain returns false when target is null. - /// + /// Verifies that TrySetValueToPropertyChain returns false when target is null. /// A task representing the asynchronous test operation. [Test] public async Task TrySetValueToPropertyChain_NullTarget_ReturnsFalse() @@ -696,7 +633,7 @@ public async Task TrySetValueToPropertyChain_ShouldThrowTrue_NullIntermediate_Th var chain = body.GetExpressionChain(); var obj = new ObjChain1 { Chain2 = new() }; // Chain3 is null - var action = () => Reflection.TrySetValueToPropertyChain(obj, chain, 42); + var action = () => Reflection.TrySetValueToPropertyChain(obj, chain, SampleValue); await Assert.That(action).ThrowsException(); } @@ -757,8 +694,8 @@ public async Task ExpressionToPropertyNames_TrueMultiArgIndexer_ReturnsCommaSepa // Create an IndexExpression with TWO constant arguments to exercise the i != 0 branch var parameter = System.Linq.Expressions.Expression.Parameter(typeof(TrueMultiArgIndexedModel), "x"); var indexer = typeof(TrueMultiArgIndexedModel).GetProperty("Item")!; - var arg0 = System.Linq.Expressions.Expression.Constant(3); - var arg1 = System.Linq.Expressions.Expression.Constant(5); + var arg0 = System.Linq.Expressions.Expression.Constant(FirstIndexArgument); + var arg1 = System.Linq.Expressions.Expression.Constant(SecondIndexArgument); var indexExpr = System.Linq.Expressions.Expression.MakeIndex( parameter, indexer, @@ -811,107 +748,64 @@ public async Task TrySetValueToPropertyChain_ReadOnlyProperty_ShouldThrowFalse_T await Assert.That(act).ThrowsException(); } - /// - /// A test model with a public field for testing field-based reflection. - /// + /// A test model with a public field for testing field-based reflection. public class FieldTestModel { - /// - /// A public field for testing field-based reflection. - /// - [SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "Test model")] - [SuppressMessage("Major Code Smell", "S2357:Fields should be private", Justification = "Test model")] - [SuppressMessage("Design", "CA1051:Do not declare visible instance fields", Justification = "Test model")] + /// A public field for testing field-based reflection. + [SuppressMessage("Design", "SST1401:Fields should be private", Justification = "A public field is what the field-reflection path under test resolves.")] public string PublicField = string.Empty; } - /// - /// A test model with an indexed property for testing index expressions. - /// - [SuppressMessage( - "Performance", - "CA1812:Avoid uninstantiated internal classes", - Justification = "Referenced only inside an inspected expression tree (never compiled), so no construction is visible to the analyzer.")] + /// A test model with an indexed property for testing index expressions. + public sealed class TrueMultiArgIndexedModel + { + /// Backing dictionary for the multi-parameter indexer. + private readonly Dictionary<(int Row, int Col), int> _data = []; + + /// Gets or sets the value at the specified row and column. + /// The row index. + /// The column index. + /// The value at the specified position. + [SuppressMessage("ReSharper", "UnusedMember.Local", Justification = "Used for testing")] + public int this[int row, int col] + { + get => _data.TryGetValue((row, col), out var val) ? val : 0; + set => _data[(row, col)] = value; + } + } + + /// A test model with an indexed property for testing index expressions. private sealed class IndexedModel { - /// - /// The first sample value stored in . - /// + /// The first sample value stored in . private const int FirstItemValue = 10; - /// - /// The second sample value stored in . - /// + /// The second sample value stored in . private const int SecondItemValue = 20; - /// - /// The third sample value stored in . - /// + /// The third sample value stored in . private const int ThirdItemValue = 30; - /// - /// Gets a list of integers for testing index expressions. - /// + /// Gets a list of integers for testing index expressions. public List Items { get; } = [FirstItemValue, SecondItemValue, ThirdItemValue]; } - /// - /// A test model with a dictionary for testing multi-argument index expressions. - /// - [SuppressMessage( - "Performance", - "CA1812:Avoid uninstantiated internal classes", - Justification = "Referenced only via typeof/reflection metadata in indexer tests; never constructed by design.")] + /// A test model with a dictionary for testing multi-argument index expressions. private sealed class MultiArgIndexedModel { - /// - /// The sample value mapped to the seeded dictionary key. - /// + /// The sample value mapped to the seeded dictionary key. private const int SeededValue = 42; - /// - /// Gets a dictionary of string-to-int mappings for testing multi-argument index expressions. - /// + /// Gets a dictionary of string-to-int mappings for testing multi-argument index expressions. [SuppressMessage("ReSharper", "UnusedMember.Local", Justification = "Used for testing")] public Dictionary Items { get; } = new() { ["key1"] = SeededValue }; } - /// - /// A test model with a true multi-parameter indexer (two int parameters). - /// - [SuppressMessage( - "Performance", - "CA1812:Avoid uninstantiated internal classes", - Justification = "Referenced only via typeof/reflection metadata in indexer tests; never constructed by design.")] - private sealed class TrueMultiArgIndexedModel - { - /// - /// Backing dictionary for the multi-parameter indexer. - /// - private readonly Dictionary<(int Row, int Col), int> _data = []; - - /// - /// Gets or sets the value at the specified row and column. - /// - /// The row index. - /// The column index. - /// The value at the specified position. - [SuppressMessage("ReSharper", "UnusedMember.Local", Justification = "Used for testing")] - public int this[int row, int col] - { - get => _data.TryGetValue((row, col), out var val) ? val : 0; - set => _data[(row, col)] = value; - } - } - - /// - /// A test model with a read-only property (getter only, no setter). - /// + /// A test model with a true multi-parameter indexer (two int parameters). + /// A test model with a read-only property (getter only, no setter). private sealed class ReadOnlyModel { - /// - /// Gets the read-only value. This property has no setter. - /// + /// Gets the read-only value. This property has no setter. public string ReadOnlyValue { get; } = "Immutable"; } } diff --git a/src/tests/ReactiveUI.Binding.Tests/Fallback/CommandBindingAffinityCheckerTests.cs b/src/tests/ReactiveUI.Binding.Tests/Fallback/CommandBindingAffinityCheckerTests.cs index 9a51139..82a2b3c 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Fallback/CommandBindingAffinityCheckerTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Fallback/CommandBindingAffinityCheckerTests.cs @@ -7,14 +7,25 @@ namespace ReactiveUI.Binding.Tests.Fallback; -/// -/// Tests for the class. -/// +/// Tests for the class. public class CommandBindingAffinityCheckerTests { - /// - /// Verifies that when no plugins are registered, the method returns false. - /// + /// The affinity the source generator's own selection is assumed to have. + private const int GeneratedAffinity = 10; + + /// A plugin affinity above , so the plugin wins. + private const int HigherPluginAffinity = 20; + + /// A plugin affinity below , so the generated binding wins. + private const int LowerPluginAffinity = 5; + + /// A second, still-losing plugin affinity used when two plugins are registered. + private const int MinorPluginAffinity = 3; + + /// A second plugin affinity used to check which of two plugins is selected. + private const int AlternatePluginAffinity = 7; + + /// Verifies that when no plugins are registered, the method returns false. /// A task representing the asynchronous test operation. [Test] public async Task HasHigherAffinityPlugin_NoPluginsRegistered_ReturnsFalse() @@ -22,7 +33,7 @@ public async Task HasHigherAffinityPlugin_NoPluginsRegistered_ReturnsFalse() AppLocator.UnregisterAll(); try { - var result = CommandBindingAffinityChecker.HasHigherAffinityPlugin(10, false); + var result = CommandBindingAffinityChecker.HasHigherAffinityPlugin(GeneratedAffinity, false); await Assert.That(result).IsFalse(); } @@ -32,10 +43,7 @@ public async Task HasHigherAffinityPlugin_NoPluginsRegistered_ReturnsFalse() } } - /// - /// Verifies that when a registered plugin has lower affinity than the generated affinity, - /// the method returns false. - /// + /// Verifies that when a registered plugin has lower affinity than the generated affinity, the method returns false. /// A task representing the asynchronous test operation. [Test] public async Task HasHigherAffinityPlugin_PluginWithLowerAffinity_ReturnsFalse() @@ -43,9 +51,9 @@ public async Task HasHigherAffinityPlugin_PluginWithLowerAffinity_ReturnsFalse() AppLocator.UnregisterAll(); try { - AppLocator.Register(() => new StubCommandBinding(5)); + AppLocator.Register(static () => new StubCommandBinding(LowerPluginAffinity)); - var result = CommandBindingAffinityChecker.HasHigherAffinityPlugin(10, false); + var result = CommandBindingAffinityChecker.HasHigherAffinityPlugin(GeneratedAffinity, false); await Assert.That(result).IsFalse(); } @@ -66,9 +74,9 @@ public async Task HasHigherAffinityPlugin_PluginWithEqualAffinity_ReturnsFalse() AppLocator.UnregisterAll(); try { - AppLocator.Register(() => new StubCommandBinding(10)); + AppLocator.Register(static () => new StubCommandBinding(GeneratedAffinity)); - var result = CommandBindingAffinityChecker.HasHigherAffinityPlugin(10, false); + var result = CommandBindingAffinityChecker.HasHigherAffinityPlugin(GeneratedAffinity, false); await Assert.That(result).IsFalse(); } @@ -78,10 +86,7 @@ public async Task HasHigherAffinityPlugin_PluginWithEqualAffinity_ReturnsFalse() } } - /// - /// Verifies that when a registered plugin has higher affinity than the generated affinity, - /// the method returns true. - /// + /// Verifies that when a registered plugin has higher affinity than the generated affinity, the method returns true. /// A task representing the asynchronous test operation. [Test] public async Task HasHigherAffinityPlugin_PluginWithHigherAffinity_ReturnsTrue() @@ -89,9 +94,9 @@ public async Task HasHigherAffinityPlugin_PluginWithHigherAffinity_ReturnsTrue() AppLocator.UnregisterAll(); try { - AppLocator.Register(() => new StubCommandBinding(20)); + AppLocator.Register(static () => new StubCommandBinding(HigherPluginAffinity)); - var result = CommandBindingAffinityChecker.HasHigherAffinityPlugin(10, false); + var result = CommandBindingAffinityChecker.HasHigherAffinityPlugin(GeneratedAffinity, false); await Assert.That(result).IsTrue(); } @@ -101,9 +106,7 @@ public async Task HasHigherAffinityPlugin_PluginWithHigherAffinity_ReturnsTrue() } } - /// - /// Verifies that the hasEventTarget parameter is correctly passed through to the plugin. - /// + /// Verifies that the hasEventTarget parameter is correctly passed through to the plugin. /// A task representing the asynchronous test operation. [Test] public async Task HasHigherAffinityPlugin_HasEventTargetTrue_PassesThroughToPlugin() @@ -111,11 +114,11 @@ public async Task HasHigherAffinityPlugin_HasEventTargetTrue_PassesThroughToPlug AppLocator.UnregisterAll(); try { - var plugin = new StubCommandBinding(20, 0); + var plugin = new StubCommandBinding(HigherPluginAffinity, 0); AppLocator.Register(() => plugin); - var resultWithEvent = CommandBindingAffinityChecker.HasHigherAffinityPlugin(10, true); - var resultWithoutEvent = CommandBindingAffinityChecker.HasHigherAffinityPlugin(10, false); + var resultWithEvent = CommandBindingAffinityChecker.HasHigherAffinityPlugin(GeneratedAffinity, true); + var resultWithoutEvent = CommandBindingAffinityChecker.HasHigherAffinityPlugin(GeneratedAffinity, false); await Assert.That(resultWithEvent).IsTrue(); await Assert.That(resultWithoutEvent).IsFalse(); @@ -137,10 +140,10 @@ public async Task HasHigherAffinityPlugin_MultiplePlugins_OnlyOneHigher_ReturnsT AppLocator.UnregisterAll(); try { - AppLocator.Register(() => new StubCommandBinding(5)); - AppLocator.Register(() => new StubCommandBinding(20)); + AppLocator.Register(static () => new StubCommandBinding(LowerPluginAffinity)); + AppLocator.Register(static () => new StubCommandBinding(HigherPluginAffinity)); - var result = CommandBindingAffinityChecker.HasHigherAffinityPlugin(10, false); + var result = CommandBindingAffinityChecker.HasHigherAffinityPlugin(GeneratedAffinity, false); await Assert.That(result).IsTrue(); } @@ -150,10 +153,7 @@ public async Task HasHigherAffinityPlugin_MultiplePlugins_OnlyOneHigher_ReturnsT } } - /// - /// Verifies that when multiple plugins are registered and none has higher affinity, - /// the method returns false. - /// + /// Verifies that when multiple plugins are registered and none has higher affinity, the method returns false. /// A task representing the asynchronous test operation. [Test] public async Task HasHigherAffinityPlugin_MultiplePlugins_NoneHigher_ReturnsFalse() @@ -161,10 +161,10 @@ public async Task HasHigherAffinityPlugin_MultiplePlugins_NoneHigher_ReturnsFals AppLocator.UnregisterAll(); try { - AppLocator.Register(() => new StubCommandBinding(3)); - AppLocator.Register(() => new StubCommandBinding(7)); + AppLocator.Register(static () => new StubCommandBinding(MinorPluginAffinity)); + AppLocator.Register(static () => new StubCommandBinding(AlternatePluginAffinity)); - var result = CommandBindingAffinityChecker.HasHigherAffinityPlugin(10, false); + var result = CommandBindingAffinityChecker.HasHigherAffinityPlugin(GeneratedAffinity, false); await Assert.That(result).IsFalse(); } @@ -174,41 +174,27 @@ public async Task HasHigherAffinityPlugin_MultiplePlugins_NoneHigher_ReturnsFals } } - /// - /// Restores default plugins by re-initializing the binding infrastructure. - /// + /// Restores default plugins by re-initializing the binding infrastructure. private static void RestoreDefaultPlugins() => RuntimeObservationFallbackTests.EnsureInitialized(); - /// - /// A stub control type used as a generic type argument in tests. - /// - [SuppressMessage("Minor Code Smell", "S2094:Classes should not be empty", Justification = "Used for testing")] - [SuppressMessage( - "Performance", - "CA1812:Avoid uninstantiated internal classes", - Justification = "Used only as a generic type argument for affinity-checker metadata dispatch; never constructed by design.")] + /// A stub control type used as a generic type argument in tests. + [SuppressMessage("Design", "SST1436:Empty type", Justification = "Only used as a generic type argument; members would not be exercised.")] private sealed class StubControl; - /// - /// A stub implementation of for testing. - /// + /// A stub implementation of for testing. private sealed class StubCommandBinding : ICreatesCommandBinding { - /// - /// The affinity to return when hasEventTarget is true. - /// + /// Thrown by stub members the affinity tests never call. + private const string NotNeededForAffinityTests = "Not needed for affinity tests."; + + /// The affinity to return when hasEventTarget is true. private readonly int _hasEventAffinity; - /// - /// The affinity to return when hasEventTarget is false. - /// + /// The affinity to return when hasEventTarget is false. private readonly int _noEventAffinity; - /// - /// Initializes a new instance of the class - /// with the same affinity for both event and non-event targets. - /// + /// Initializes a new instance of the class with the same affinity for both event and non-event targets. /// The affinity to return for all calls. public StubCommandBinding(int affinity) { @@ -216,10 +202,7 @@ public StubCommandBinding(int affinity) _noEventAffinity = affinity; } - /// - /// Initializes a new instance of the class - /// with different affinities for event and non-event targets. - /// + /// Initializes a new instance of the class with different affinities for event and non-event targets. /// The affinity to return when hasEventTarget is true. /// The affinity to return when hasEventTarget is false. public StubCommandBinding(int hasEventAffinity, int noEventAffinity) @@ -229,10 +212,7 @@ public StubCommandBinding(int hasEventAffinity, int noEventAffinity) } /// - [SuppressMessage( - "Major Code Smell", - "S4018:Generic methods should provide type parameter for type inference", - Justification = "Type parameter is dictated by the implemented interface and is not inferable from the arguments.")] + [SuppressMessage("Design", "SST1452:Unused type parameter", Justification = "Dictated by the interface this test stub implements.")] public int GetAffinityForObject(bool hasEventTarget) => hasEventTarget ? _hasEventAffinity : _noEventAffinity; @@ -242,20 +222,17 @@ public int GetAffinityForObject(bool hasEventTarget) => T? target, IObservable commandParameter) where T : class => - throw new NotSupportedException("Not needed for affinity tests."); + throw new NotSupportedException(NotNeededForAffinityTests); /// - [SuppressMessage( - "Major Code Smell", - "S4018:Generic methods should provide type parameter for type inference", - Justification = "Type parameter is dictated by the implemented interface and is not inferable from the arguments.")] + [SuppressMessage("Design", "SST1452:Unused type parameter", Justification = "Dictated by the interface this test stub implements.")] public IDisposable? BindCommandToObject( ICommand? command, T? target, IObservable commandParameter, string eventName) where T : class => - throw new NotSupportedException("Not needed for affinity tests."); + throw new NotSupportedException(NotNeededForAffinityTests); /// public IDisposable? BindCommandToObject( @@ -266,6 +243,6 @@ public int GetAffinityForObject(bool hasEventTarget) => Action> removeHandler) where T : class where TEventArgs : EventArgs => - throw new NotSupportedException("Not needed for affinity tests."); + throw new NotSupportedException(NotNeededForAffinityTests); } } diff --git a/src/tests/ReactiveUI.Binding.Tests/Fallback/ObservationAffinityCheckerTests.cs b/src/tests/ReactiveUI.Binding.Tests/Fallback/ObservationAffinityCheckerTests.cs index 3d21bb3..0bc9e28 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Fallback/ObservationAffinityCheckerTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Fallback/ObservationAffinityCheckerTests.cs @@ -7,25 +7,34 @@ namespace ReactiveUI.Binding.Tests.Fallback; -/// -/// Tests for the class. -/// +/// Tests for the class. public class ObservationAffinityCheckerTests { - /// - /// Verifies that passing a null type throws . - /// + /// The affinity the source generator's own selection is assumed to have. + private const int GeneratedAffinity = 10; + + /// A plugin affinity above , so the plugin wins. + private const int HigherPluginAffinity = 20; + + /// A plugin affinity below , so the generated binding wins. + private const int LowerPluginAffinity = 5; + + /// A second, still-losing plugin affinity used when two plugins are registered. + private const int MinorPluginAffinity = 3; + + /// A second plugin affinity used to check which of two plugins is selected. + private const int AlternatePluginAffinity = 7; + + /// Verifies that passing a null type throws . /// A task representing the asynchronous test operation. [Test] public async Task HasHigherAffinityPlugin_NullType_ThrowsArgumentNullException() { - var action = () => ObservationAffinityChecker.HasHigherAffinityPlugin(null!, 10, false); + var action = static () => ObservationAffinityChecker.HasHigherAffinityPlugin(null!, GeneratedAffinity, false); await Assert.That(action).ThrowsExactly(); } - /// - /// Verifies that when no plugins are registered, the method returns false. - /// + /// Verifies that when no plugins are registered, the method returns false. /// A task representing the asynchronous test operation. [Test] public async Task HasHigherAffinityPlugin_NoPluginsRegistered_ReturnsFalse() @@ -33,7 +42,7 @@ public async Task HasHigherAffinityPlugin_NoPluginsRegistered_ReturnsFalse() AppLocator.UnregisterAll(); try { - var result = ObservationAffinityChecker.HasHigherAffinityPlugin(typeof(string), 10, false); + var result = ObservationAffinityChecker.HasHigherAffinityPlugin(typeof(string), GeneratedAffinity, false); await Assert.That(result).IsFalse(); } @@ -43,10 +52,7 @@ public async Task HasHigherAffinityPlugin_NoPluginsRegistered_ReturnsFalse() } } - /// - /// Verifies that when all registered plugins have lower affinity than the generated affinity, - /// the method returns false. - /// + /// Verifies that when all registered plugins have lower affinity than the generated affinity, the method returns false. /// A task representing the asynchronous test operation. [Test] public async Task HasHigherAffinityPlugin_PluginWithLowerAffinity_ReturnsFalse() @@ -54,9 +60,9 @@ public async Task HasHigherAffinityPlugin_PluginWithLowerAffinity_ReturnsFalse() AppLocator.UnregisterAll(); try { - AppLocator.Register(() => new StubObservableForProperty(5)); + AppLocator.Register(static () => new StubObservableForProperty(LowerPluginAffinity)); - var result = ObservationAffinityChecker.HasHigherAffinityPlugin(typeof(string), 10, false); + var result = ObservationAffinityChecker.HasHigherAffinityPlugin(typeof(string), GeneratedAffinity, false); await Assert.That(result).IsFalse(); } @@ -77,9 +83,9 @@ public async Task HasHigherAffinityPlugin_PluginWithEqualAffinity_ReturnsFalse() AppLocator.UnregisterAll(); try { - AppLocator.Register(() => new StubObservableForProperty(10)); + AppLocator.Register(static () => new StubObservableForProperty(GeneratedAffinity)); - var result = ObservationAffinityChecker.HasHigherAffinityPlugin(typeof(string), 10, false); + var result = ObservationAffinityChecker.HasHigherAffinityPlugin(typeof(string), GeneratedAffinity, false); await Assert.That(result).IsFalse(); } @@ -89,10 +95,7 @@ public async Task HasHigherAffinityPlugin_PluginWithEqualAffinity_ReturnsFalse() } } - /// - /// Verifies that when a registered plugin has higher affinity than the generated affinity, - /// the method returns true. - /// + /// Verifies that when a registered plugin has higher affinity than the generated affinity, the method returns true. /// A task representing the asynchronous test operation. [Test] public async Task HasHigherAffinityPlugin_PluginWithHigherAffinity_ReturnsTrue() @@ -100,9 +103,9 @@ public async Task HasHigherAffinityPlugin_PluginWithHigherAffinity_ReturnsTrue() AppLocator.UnregisterAll(); try { - AppLocator.Register(() => new StubObservableForProperty(20)); + AppLocator.Register(static () => new StubObservableForProperty(HigherPluginAffinity)); - var result = ObservationAffinityChecker.HasHigherAffinityPlugin(typeof(string), 10, false); + var result = ObservationAffinityChecker.HasHigherAffinityPlugin(typeof(string), GeneratedAffinity, false); await Assert.That(result).IsTrue(); } @@ -112,9 +115,7 @@ public async Task HasHigherAffinityPlugin_PluginWithHigherAffinity_ReturnsTrue() } } - /// - /// Verifies that the beforeChanged parameter is correctly passed through to the plugin. - /// + /// Verifies that the beforeChanged parameter is correctly passed through to the plugin. /// A task representing the asynchronous test operation. [Test] public async Task HasHigherAffinityPlugin_BeforeChangedTrue_PassesThroughToPlugin() @@ -122,11 +123,11 @@ public async Task HasHigherAffinityPlugin_BeforeChangedTrue_PassesThroughToPlugi AppLocator.UnregisterAll(); try { - var plugin = new StubObservableForProperty(20, 0); + var plugin = new StubObservableForProperty(HigherPluginAffinity, 0); AppLocator.Register(() => plugin); - var resultBeforeChanged = ObservationAffinityChecker.HasHigherAffinityPlugin(typeof(string), 10, true); - var resultAfterChanged = ObservationAffinityChecker.HasHigherAffinityPlugin(typeof(string), 10, false); + var resultBeforeChanged = ObservationAffinityChecker.HasHigherAffinityPlugin(typeof(string), GeneratedAffinity, true); + var resultAfterChanged = ObservationAffinityChecker.HasHigherAffinityPlugin(typeof(string), GeneratedAffinity, false); await Assert.That(resultBeforeChanged).IsTrue(); await Assert.That(resultAfterChanged).IsFalse(); @@ -148,10 +149,10 @@ public async Task HasHigherAffinityPlugin_MultiplePlugins_OnlyOneHigher_ReturnsT AppLocator.UnregisterAll(); try { - AppLocator.Register(() => new StubObservableForProperty(5)); - AppLocator.Register(() => new StubObservableForProperty(20)); + AppLocator.Register(static () => new StubObservableForProperty(LowerPluginAffinity)); + AppLocator.Register(static () => new StubObservableForProperty(HigherPluginAffinity)); - var result = ObservationAffinityChecker.HasHigherAffinityPlugin(typeof(string), 10, false); + var result = ObservationAffinityChecker.HasHigherAffinityPlugin(typeof(string), GeneratedAffinity, false); await Assert.That(result).IsTrue(); } @@ -161,10 +162,7 @@ public async Task HasHigherAffinityPlugin_MultiplePlugins_OnlyOneHigher_ReturnsT } } - /// - /// Verifies that when multiple plugins are registered and none has higher affinity, - /// the method returns false. - /// + /// Verifies that when multiple plugins are registered and none has higher affinity, the method returns false. /// A task representing the asynchronous test operation. [Test] public async Task HasHigherAffinityPlugin_MultiplePlugins_NoneHigher_ReturnsFalse() @@ -172,10 +170,10 @@ public async Task HasHigherAffinityPlugin_MultiplePlugins_NoneHigher_ReturnsFals AppLocator.UnregisterAll(); try { - AppLocator.Register(() => new StubObservableForProperty(3)); - AppLocator.Register(() => new StubObservableForProperty(7)); + AppLocator.Register(static () => new StubObservableForProperty(MinorPluginAffinity)); + AppLocator.Register(static () => new StubObservableForProperty(AlternatePluginAffinity)); - var result = ObservationAffinityChecker.HasHigherAffinityPlugin(typeof(string), 10, false); + var result = ObservationAffinityChecker.HasHigherAffinityPlugin(typeof(string), GeneratedAffinity, false); await Assert.That(result).IsFalse(); } @@ -185,31 +183,20 @@ public async Task HasHigherAffinityPlugin_MultiplePlugins_NoneHigher_ReturnsFals } } - /// - /// Restores default plugins by re-initializing the binding infrastructure. - /// + /// Restores default plugins by re-initializing the binding infrastructure. private static void RestoreDefaultPlugins() => RuntimeObservationFallbackTests.EnsureInitialized(); - /// - /// A stub implementation of for testing. - /// + /// A stub implementation of for testing. private sealed class StubObservableForProperty : ICreatesObservableForProperty { - /// - /// The affinity to return when beforeChanged is true. - /// + /// The affinity to return when beforeChanged is true. private readonly int _beforeChangedAffinity; - /// - /// The affinity to return when beforeChanged is false. - /// + /// The affinity to return when beforeChanged is false. private readonly int _afterChangedAffinity; - /// - /// Initializes a new instance of the class - /// with the same affinity for both before and after change. - /// + /// Initializes a new instance of the class with the same affinity for both before and after change. /// The affinity to return for all calls. public StubObservableForProperty(int affinity) { @@ -217,10 +204,7 @@ public StubObservableForProperty(int affinity) _afterChangedAffinity = affinity; } - /// - /// Initializes a new instance of the class - /// with different affinities for before and after change. - /// + /// Initializes a new instance of the class with different affinities for before and after change. /// The affinity to return when beforeChanged is true. /// The affinity to return when beforeChanged is false. public StubObservableForProperty(int beforeChangedAffinity, int afterChangedAffinity) diff --git a/src/tests/ReactiveUI.Binding.Tests/Fallback/RuntimeObservationFallbackTests.cs b/src/tests/ReactiveUI.Binding.Tests/Fallback/RuntimeObservationFallbackTests.cs index a33b527..899ef7b 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Fallback/RuntimeObservationFallbackTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Fallback/RuntimeObservationFallbackTests.cs @@ -9,39 +9,35 @@ namespace ReactiveUI.Binding.Tests.Fallback; -/// -/// Tests for the class. -/// +/// Tests for the class. public class RuntimeObservationFallbackTests { - /// - /// A sample name value used across the multi-property tests. - /// + /// The value the view model starts with. + private const string InitialValue = "Initial"; + + /// The value assigned to trigger a notification. + private const string ChangedValue = "Changed"; + + /// A sample name value used across the multi-property tests. private const string SampleName = "Alice"; - /// - /// A sample age value used across the multi-property tests. - /// + /// A sample age value used across the multi-property tests. private const int SampleAge = 30; /// The sample city value used across the fallback tests. private const string SampleCity = "Seattle"; - /// - /// The expected number of emissions when an initial value plus one change are observed. - /// + /// The expected number of emissions when an initial value plus one change are observed. private const int ExpectedTwoEmissions = 2; - /// - /// Verifies that WhenChanged emits the initial value and subsequent changes. - /// + /// Verifies that WhenChanged emits the initial value and subsequent changes. /// A task representing the asynchronous test operation. [Test] public async Task WhenChanged_SingleProperty_EmitsInitialAndChanges() { EnsureInitialized(); - var vm = new TestViewModel { Name = "Initial" }; + var vm = new TestViewModel { Name = InitialValue }; var values = new List(); using var sub = RuntimeObservationFallback.WhenChanged( @@ -49,23 +45,21 @@ public async Task WhenChanged_SingleProperty_EmitsInitialAndChanges() x => x.Name) .Subscribe(values.Add); - vm.Name = "Changed"; + vm.Name = ChangedValue; await Assert.That(values.Count).IsGreaterThanOrEqualTo(ExpectedTwoEmissions); - await Assert.That(values[0]).IsEqualTo("Initial"); - await Assert.That(values[1]).IsEqualTo("Changed"); + await Assert.That(values[0]).IsEqualTo(InitialValue); + await Assert.That(values[1]).IsEqualTo(ChangedValue); } - /// - /// Verifies that WhenChanging emits before-change notifications. - /// + /// Verifies that WhenChanging emits before-change notifications. /// A task representing the asynchronous test operation. [Test] public async Task WhenChanging_SingleProperty_EmitsBeforeChange() { EnsureInitialized(); - var vm = new TestViewModel { Name = "Initial" }; + var vm = new TestViewModel { Name = InitialValue }; var values = new List(); using var sub = RuntimeObservationFallback.WhenChanging( @@ -73,15 +67,13 @@ public async Task WhenChanging_SingleProperty_EmitsBeforeChange() x => x.Name) .Subscribe(values.Add); - vm.Name = "Changed"; + vm.Name = ChangedValue; // Before-change should emit the old value at the time of notification await Assert.That(values.Count).IsGreaterThanOrEqualTo(1); } - /// - /// Verifies that WhenAnyValue emits the initial and subsequent values. - /// + /// Verifies that WhenAnyValue emits the initial and subsequent values. /// A task representing the asynchronous test operation. [Test] public async Task WhenAnyValue_SingleProperty_EmitsValues() @@ -102,9 +94,7 @@ public async Task WhenAnyValue_SingleProperty_EmitsValues() await Assert.That(values[0]).IsEqualTo("Start"); } - /// - /// Verifies that WhenChanged with two properties emits tuples. - /// + /// Verifies that WhenChanged with two properties emits tuples. /// A task representing the asynchronous test operation. [Test] public async Task WhenChanged_TwoProperties_EmitsTuples() @@ -125,9 +115,7 @@ public async Task WhenChanged_TwoProperties_EmitsTuples() await Assert.That(values[0].Value2).IsEqualTo(SampleAge); } - /// - /// Verifies that WhenChanged with three properties emits tuples. - /// + /// Verifies that WhenChanged with three properties emits tuples. /// A task representing the asynchronous test operation. [Test] public async Task WhenChanged_ThreeProperties_EmitsTuples() @@ -150,9 +138,7 @@ public async Task WhenChanged_ThreeProperties_EmitsTuples() await Assert.That(values[0].Value3).IsEqualTo(SampleCity); } - /// - /// Verifies that WhenChanged emits after property changes with three properties. - /// + /// Verifies that WhenChanged emits after property changes with three properties. /// A task representing the asynchronous test operation. [Test] public async Task WhenChanged_ThreeProperties_UpdatesOnChange() @@ -175,9 +161,7 @@ public async Task WhenChanged_ThreeProperties_UpdatesOnChange() await Assert.That(values[^1].Value1).IsEqualTo("Bob"); } - /// - /// Verifies that WhenChanging with two properties emits tuples. - /// + /// Verifies that WhenChanging with two properties emits tuples. /// A task representing the asynchronous test operation. [Test] public async Task WhenChanging_TwoProperties_EmitsTuples() @@ -198,9 +182,7 @@ public async Task WhenChanging_TwoProperties_EmitsTuples() await Assert.That(values.Count).IsGreaterThanOrEqualTo(1); } - /// - /// Verifies that WhenChanging with three properties emits tuples. - /// + /// Verifies that WhenChanging with three properties emits tuples. /// A task representing the asynchronous test operation. [Test] public async Task WhenChanging_ThreeProperties_EmitsTuples() @@ -222,9 +204,7 @@ public async Task WhenChanging_ThreeProperties_EmitsTuples() await Assert.That(values.Count).IsGreaterThanOrEqualTo(1); } - /// - /// Verifies that WhenAnyValue with two properties emits tuples. - /// + /// Verifies that WhenAnyValue with two properties emits tuples. /// A task representing the asynchronous test operation. [Test] public async Task WhenAnyValue_TwoProperties_EmitsTuples() @@ -245,9 +225,7 @@ public async Task WhenAnyValue_TwoProperties_EmitsTuples() await Assert.That(values[0].Value2).IsEqualTo(SampleAge); } - /// - /// Verifies that WhenAnyValue with three properties emits tuples. - /// + /// Verifies that WhenAnyValue with three properties emits tuples. /// A task representing the asynchronous test operation. [Test] public async Task WhenAnyValue_ThreeProperties_EmitsTuples() @@ -270,9 +248,7 @@ public async Task WhenAnyValue_ThreeProperties_EmitsTuples() await Assert.That(values[0].Value3).IsEqualTo(SampleCity); } - /// - /// Verifies that WhenAnyValue with two properties updates on change. - /// + /// Verifies that WhenAnyValue with two properties updates on change. /// A task representing the asynchronous test operation. [Test] public async Task WhenAnyValue_TwoProperties_UpdatesOnChange() @@ -294,13 +270,11 @@ public async Task WhenAnyValue_TwoProperties_UpdatesOnChange() await Assert.That(values[^1].Value1).IsEqualTo("Bob"); } - /// - /// Resets and initializes the ReactiveUI binding infrastructure for testing. - /// + /// Resets and initializes the ReactiveUI binding infrastructure for testing. internal static void EnsureInitialized() { RxBindingBuilder.ResetForTesting(); - RxBindingBuilder.CreateReactiveUIBindingBuilder() + _ = RxBindingBuilder.CreateReactiveUIBindingBuilder() .WithCoreServices() .BuildApp(); } diff --git a/src/tests/ReactiveUI.Binding.Tests/Interactions/InteractionContextTests.cs b/src/tests/ReactiveUI.Binding.Tests/Interactions/InteractionContextTests.cs index 6409e5f..30360a5 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Interactions/InteractionContextTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Interactions/InteractionContextTests.cs @@ -4,29 +4,19 @@ namespace ReactiveUI.Binding.Tests.Interactions; -/// -/// Tests for . -/// +/// Tests for . public class InteractionContextTests { - /// - /// A sample input value used across the interaction-context tests. - /// + /// A sample input value used across the interaction-context tests. private const string SampleInput = "input"; - /// - /// A sample output value set on the interaction context. - /// + /// A sample output value set on the interaction context. private const int SampleOutput = 42; - /// - /// A secondary output value used to verify SetOutput cannot be called twice. - /// + /// A secondary output value used to verify SetOutput cannot be called twice. private const int SecondOutput = 2; - /// - /// Verifies that Input returns the value passed at construction. - /// + /// Verifies that Input returns the value passed at construction. /// A representing the asynchronous unit test. [Test] public async Task Input_ReturnsConstructionValue() @@ -35,9 +25,7 @@ public async Task Input_ReturnsConstructionValue() await Assert.That(context.Input).IsEqualTo("hello"); } - /// - /// Verifies that IsHandled is false before SetOutput is called. - /// + /// Verifies that IsHandled is false before SetOutput is called. /// A representing the asynchronous unit test. [Test] public async Task IsHandled_FalseBeforeSetOutput() @@ -46,9 +34,7 @@ public async Task IsHandled_FalseBeforeSetOutput() await Assert.That(context.IsHandled).IsFalse(); } - /// - /// Verifies that SetOutput sets IsHandled to true. - /// + /// Verifies that SetOutput sets IsHandled to true. /// A representing the asynchronous unit test. [Test] public async Task SetOutput_SetsIsHandledTrue() @@ -58,9 +44,7 @@ public async Task SetOutput_SetsIsHandledTrue() await Assert.That(context.IsHandled).IsTrue(); } - /// - /// Verifies that GetOutput returns the value set by SetOutput. - /// + /// Verifies that GetOutput returns the value set by SetOutput. /// A representing the asynchronous unit test. [Test] public async Task GetOutput_ReturnsSetValue() @@ -70,9 +54,7 @@ public async Task GetOutput_ReturnsSetValue() await Assert.That(context.GetOutput()).IsEqualTo(SampleOutput); } - /// - /// Verifies that calling SetOutput twice throws InvalidOperationException. - /// + /// Verifies that calling SetOutput twice throws InvalidOperationException. /// A representing the asynchronous unit test. [Test] public async Task SetOutput_CalledTwice_Throws() @@ -82,9 +64,7 @@ public async Task SetOutput_CalledTwice_Throws() await Assert.That(() => context.SetOutput(SecondOutput)).Throws(); } - /// - /// Verifies that GetOutput throws when output has not been set. - /// + /// Verifies that GetOutput throws when output has not been set. /// A representing the asynchronous unit test. [Test] public async Task GetOutput_BeforeSetOutput_Throws() @@ -93,10 +73,7 @@ public async Task GetOutput_BeforeSetOutput_Throws() await Assert.That(context.GetOutput).Throws(); } - /// - /// Creates an . The internal constructor is - /// directly accessible to this assembly via InternalsVisibleTo. - /// + /// Creates an . The internal constructor is directly accessible to this assembly via InternalsVisibleTo. /// The input value for the interaction context. /// A new instance. private static InteractionContext CreateContext(string input) => diff --git a/src/tests/ReactiveUI.Binding.Tests/Interactions/InteractionTests.cs b/src/tests/ReactiveUI.Binding.Tests/Interactions/InteractionTests.cs index 3a8c49f..57b8fb5 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Interactions/InteractionTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Interactions/InteractionTests.cs @@ -4,49 +4,40 @@ namespace ReactiveUI.Binding.Tests.Interactions; -/// -/// Tests for . -/// +/// Tests for . public class InteractionTests { - /// - /// The expected output of the synchronous handler (the length of "hello"). - /// + /// The result the first registered handler produces. + private const string FirstHandlerResult = "first"; + + /// The expected output of the synchronous handler (the length of "hello"). private const int HelloLength = 5; - /// - /// A sample output value set by handlers under test. - /// + /// A sample output value set by handlers under test. private const int SampleOutput = 42; - /// - /// An alternative output value used by the Action-overload test. - /// + /// An alternative output value used by the Action-overload test. private const int ActionOutput = 99; - /// - /// Verifies that Handle returns the output set by a synchronous handler. - /// + /// Verifies that Handle returns the output set by a synchronous handler. /// A representing the asynchronous unit test. [Test] public async Task Handle_SyncHandler_ReturnsOutput() { var interaction = new Interaction(); - using var registration = interaction.RegisterHandler(ctx => ctx.SetOutput(ctx.Input.Length)); + using var registration = interaction.RegisterHandler(static ctx => ctx.SetOutput(ctx.Input.Length)); var result = await interaction.Handle("hello"); await Assert.That(result).IsEqualTo(HelloLength); } - /// - /// Verifies that Handle returns the output set by an async task handler. - /// + /// Verifies that Handle returns the output set by an async task handler. /// A representing the asynchronous unit test. [Test] public async Task Handle_TaskHandler_ReturnsOutput() { var interaction = new Interaction(); - using var registration = interaction.RegisterHandler(async ctx => + using var registration = interaction.RegisterHandler(static async ctx => { await Task.Yield(); ctx.SetOutput(true); @@ -56,15 +47,13 @@ public async Task Handle_TaskHandler_ReturnsOutput() await Assert.That(result).IsTrue(); } - /// - /// Verifies that Handle returns the output set by an observable handler. - /// + /// Verifies that Handle returns the output set by an observable handler. /// A representing the asynchronous unit test. [Test] public async Task Handle_ObservableHandler_ReturnsOutput() { var interaction = new Interaction(); - using var registration = interaction.RegisterHandler(ctx => + using var registration = interaction.RegisterHandler(static ctx => { ctx.SetOutput(SampleOutput); return new Binding.Observables.ReturnObservable(0); @@ -74,24 +63,20 @@ public async Task Handle_ObservableHandler_ReturnsOutput() await Assert.That(result).IsEqualTo(SampleOutput); } - /// - /// Verifies that handlers are invoked in LIFO order. - /// + /// Verifies that handlers are invoked in LIFO order. /// A representing the asynchronous unit test. [Test] public async Task Handle_MultipleHandlers_LIFOOrder() { var interaction = new Interaction(); - using var first = interaction.RegisterHandler(ctx => ctx.SetOutput("first")); - using var second = interaction.RegisterHandler(ctx => ctx.SetOutput("second")); + using var first = interaction.RegisterHandler(static ctx => ctx.SetOutput(FirstHandlerResult)); + using var second = interaction.RegisterHandler(static ctx => ctx.SetOutput("second")); var result = await interaction.Handle("input"); await Assert.That(result).IsEqualTo("second"); } - /// - /// Verifies that Handle throws UnhandledInteractionException when no handler calls SetOutput. - /// + /// Verifies that Handle throws UnhandledInteractionException when no handler calls SetOutput. /// A representing the asynchronous unit test. [Test] public async Task Handle_NoHandlers_ThrowsUnhandledInteractionException() @@ -101,42 +86,36 @@ await Assert.That(() => interaction.Handle("test")) .ThrowsExactly>(); } - /// - /// Verifies that disposing the registration unregisters the handler. - /// + /// Verifies that disposing the registration unregisters the handler. /// A representing the asynchronous unit test. [Test] public async Task Dispose_UnregistersHandler() { var interaction = new Interaction(); - var registration = interaction.RegisterHandler(ctx => ctx.SetOutput(SampleOutput)); + var registration = interaction.RegisterHandler(static ctx => ctx.SetOutput(SampleOutput)); registration.Dispose(); await Assert.That(() => interaction.Handle("test")) .ThrowsExactly>(); } - /// - /// Verifies that a handler that doesn't call SetOutput is skipped, and the next handler is tried. - /// + /// Verifies that a handler that doesn't call SetOutput is skipped, and the next handler is tried. /// A representing the asynchronous unit test. [Test] public async Task Handle_HandlerSkips_FallsToNext() { var interaction = new Interaction(); - using var first = interaction.RegisterHandler(ctx => ctx.SetOutput("first")); - using var second = interaction.RegisterHandler(ctx => + using var first = interaction.RegisterHandler(static ctx => ctx.SetOutput(FirstHandlerResult)); + using var second = interaction.RegisterHandler(static ctx => { // Intentionally don't call SetOutput — skip }); var result = await interaction.Handle("input"); - await Assert.That(result).IsEqualTo("first"); + await Assert.That(result).IsEqualTo(FirstHandlerResult); } - /// - /// Verifies that RegisterHandler(Action) throws ArgumentNullException when handler is null. - /// + /// Verifies that RegisterHandler(Action) throws ArgumentNullException when handler is null. /// A representing the asynchronous unit test. [Test] public async Task RegisterHandler_Action_NullHandler_Throws() @@ -146,9 +125,7 @@ await Assert.That(() => interaction.RegisterHandler((Action(); } - /// - /// Verifies that RegisterHandler(Func<Task>) throws ArgumentNullException when handler is null. - /// + /// Verifies that RegisterHandler(Func<Task>) throws ArgumentNullException when handler is null. /// A representing the asynchronous unit test. [Test] public async Task RegisterHandler_TaskHandler_NullHandler_Throws() @@ -158,9 +135,7 @@ await Assert.That(() => interaction.RegisterHandler((Func(); } - /// - /// Verifies that RegisterHandler(observable) throws ArgumentNullException when handler is null. - /// + /// Verifies that RegisterHandler(observable) throws ArgumentNullException when handler is null. /// A representing the asynchronous unit test. [Test] public async Task RegisterHandler_ObservableHandler_NullHandler_Throws() @@ -180,7 +155,7 @@ await Assert.That(() => public async Task Handle_ObservableHandler_OnError_PropagatesException() { var interaction = new Interaction(); - using var registration = interaction.RegisterHandler(ctx => + using var registration = interaction.RegisterHandler(static ctx => { ctx.SetOutput(true); return new ErrorObservable(new InvalidOperationException("test error")); @@ -191,24 +166,21 @@ await Assert.That(() => interaction.Handle("test")) .WithMessage("test error", StringComparison.Ordinal); } - /// - /// Verifies that the Action overload of RegisterHandler sets the output correctly. - /// + /// Verifies that the Action overload of RegisterHandler sets the output correctly. /// A representing the asynchronous unit test. [Test] public async Task RegisterHandler_Action_SetsOutput() { var interaction = new Interaction(); - using var registration = interaction.RegisterHandler(ctx => ctx.SetOutput(ActionOutput)); + using var registration = interaction.RegisterHandler(static ctx => ctx.SetOutput(ActionOutput)); var result = await interaction.Handle("test"); await Assert.That(result).IsEqualTo(ActionOutput); } - /// - /// An observable that immediately errors on subscribe. Used to test OnError path. - /// + /// An observable that immediately errors on subscribe. Used to test OnError path. /// The element type. + /// The exception this observable faults with on subscription. private sealed class ErrorObservable(Exception error) : IObservable { /// diff --git a/src/tests/ReactiveUI.Binding.Tests/Interactions/UnhandledInteractionExceptionTests.cs b/src/tests/ReactiveUI.Binding.Tests/Interactions/UnhandledInteractionExceptionTests.cs index acffaee..efd8e2f 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Interactions/UnhandledInteractionExceptionTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Interactions/UnhandledInteractionExceptionTests.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding.Tests.Interactions; -/// -/// Tests for . -/// +/// Tests for . public class UnhandledInteractionExceptionTests { - /// - /// Verifies that the parameterless constructor creates a valid instance. - /// + /// Verifies that the parameterless constructor creates a valid instance. /// A representing the asynchronous unit test. [Test] public async Task ParameterlessConstructor_CreatesInstance() @@ -21,9 +17,7 @@ public async Task ParameterlessConstructor_CreatesInstance() await Assert.That(ex.Message).IsNotNull(); } - /// - /// Verifies that the message constructor sets the message. - /// + /// Verifies that the message constructor sets the message. /// A representing the asynchronous unit test. [Test] public async Task MessageConstructor_SetsMessage() @@ -33,9 +27,7 @@ public async Task MessageConstructor_SetsMessage() await Assert.That(ex.Interaction).IsNull(); } - /// - /// Verifies that the message+innerException constructor sets both properties. - /// + /// Verifies that the message+innerException constructor sets both properties. /// A representing the asynchronous unit test. [Test] public async Task MessageAndInnerExceptionConstructor_SetsBoth() diff --git a/src/tests/ReactiveUI.Binding.Tests/ObservableForProperty/BasicRuntimeTests.cs b/src/tests/ReactiveUI.Binding.Tests/ObservableForProperty/BasicRuntimeTests.cs index 8b8c2f5..54bd74a 100644 --- a/src/tests/ReactiveUI.Binding.Tests/ObservableForProperty/BasicRuntimeTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/ObservableForProperty/BasicRuntimeTests.cs @@ -4,19 +4,13 @@ namespace ReactiveUI.Binding.Tests.ObservableForProperty; -/// -/// Basic tests for the runtime library types. -/// +/// Basic tests for the runtime library types. public class BasicRuntimeTests { - /// - /// The expected value used when constructing and asserting an observed change. - /// + /// The expected value used when constructing and asserting an observed change. private const int ExpectedValue = 42; - /// - /// Verifies that ObservedChange can be constructed and its properties accessed. - /// + /// Verifies that ObservedChange can be constructed and its properties accessed. /// A task representing the asynchronous test operation. [Test] public async Task ObservedChange_Properties() @@ -28,9 +22,7 @@ public async Task ObservedChange_Properties() await Assert.That(change.Expression).IsNull(); } - /// - /// Verifies that the BindingDirection enum defines the expected members at runtime. - /// + /// Verifies that the BindingDirection enum defines the expected members at runtime. /// A task representing the asynchronous test operation. [Test] public async Task BindingDirection_Values() diff --git a/src/tests/ReactiveUI.Binding.Tests/ObservableForProperty/INPCObservableForPropertyTests.cs b/src/tests/ReactiveUI.Binding.Tests/ObservableForProperty/INPCObservableForPropertyTests.cs index 3d5fd36..f86da4c 100644 --- a/src/tests/ReactiveUI.Binding.Tests/ObservableForProperty/INPCObservableForPropertyTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/ObservableForProperty/INPCObservableForPropertyTests.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for full license information. using System.ComponentModel; +using System.Reflection; using ReactiveUI.Binding.Expressions; using ReactiveUI.Binding.ObservableForProperty; using ReactiveUI.Binding.Tests.TestModels; @@ -10,34 +11,22 @@ namespace ReactiveUI.Binding.Tests.ObservableForProperty; -/// -/// Tests for the class. -/// +/// Tests for the class. public class INPCObservableForPropertyTests { - /// - /// The affinity score returned for INotifyPropertyChanged-compatible types. - /// + /// The affinity score returned for INotifyPropertyChanged-compatible types. private const int InpcAffinity = 5; - /// - /// A sample name value assigned during notification tests. - /// + /// A sample name value assigned during notification tests. private const string SampleName = "Alice"; - /// - /// A sample indexer value used during notification tests. - /// + /// A sample indexer value used during notification tests. private const string SampleValue = "value"; - /// - /// The name of the non-indexer property used in PropertyChanging tests. - /// + /// The name of the non-indexer property used in PropertyChanging tests. private const string SomePropName = "SomeProp"; - /// - /// A sample age value assigned to an unrelated property. - /// + /// A sample age value assigned to an unrelated property. private const int SampleAge = 30; /// @@ -46,9 +35,7 @@ public class INPCObservableForPropertyTests /// private const int ExpectedNonDistinctCount = 4; - /// - /// Verifies affinity is 5 for types implementing INotifyPropertyChanged. - /// + /// Verifies affinity is 5 for types implementing INotifyPropertyChanged. /// A task representing the asynchronous test operation. [Test] public async Task GetAffinityForObject_INPCType_Returns5() @@ -60,9 +47,7 @@ public async Task GetAffinityForObject_INPCType_Returns5() await Assert.That(affinity).IsEqualTo(InpcAffinity); } - /// - /// Verifies affinity is 5 for INotifyPropertyChanging when beforeChanged is true. - /// + /// Verifies affinity is 5 for INotifyPropertyChanging when beforeChanged is true. /// A task representing the asynchronous test operation. [Test] public async Task GetAffinityForObject_INPCChangingType_Returns5ForBeforeChanged() @@ -74,9 +59,7 @@ public async Task GetAffinityForObject_INPCChangingType_Returns5ForBeforeChanged await Assert.That(affinity).IsEqualTo(InpcAffinity); } - /// - /// Verifies affinity is 0 for POCO types. - /// + /// Verifies affinity is 0 for POCO types. /// A task representing the asynchronous test operation. [Test] public async Task GetAffinityForObject_PocoType_Returns0() @@ -88,9 +71,7 @@ public async Task GetAffinityForObject_PocoType_Returns0() await Assert.That(affinity).IsEqualTo(0); } - /// - /// Verifies that GetNotificationForProperty emits when a property changes. - /// + /// Verifies that GetNotificationForProperty emits when a property changes. /// A task representing the asynchronous test operation. [Test] public async Task GetNotificationForProperty_PropertyChanged_EmitsNotification() @@ -110,9 +91,7 @@ public async Task GetNotificationForProperty_PropertyChanged_EmitsNotification() await Assert.That(emitted).IsTrue(); } - /// - /// Verifies that GetNotificationForProperty emits before-change notifications. - /// + /// Verifies that GetNotificationForProperty emits before-change notifications. /// A task representing the asynchronous test operation. [Test] public async Task GetNotificationForProperty_BeforeChanged_EmitsNotification() @@ -132,9 +111,7 @@ public async Task GetNotificationForProperty_BeforeChanged_EmitsNotification() await Assert.That(emitted).IsTrue(); } - /// - /// Verifies that GetNotificationForProperty filters by property name. - /// + /// Verifies that GetNotificationForProperty filters by property name. /// A task representing the asynchronous test operation. [Test] public async Task GetNotificationForProperty_DifferentProperty_DoesNotEmit() @@ -155,9 +132,7 @@ public async Task GetNotificationForProperty_DifferentProperty_DoesNotEmit() await Assert.That(emitted).IsFalse(); } - /// - /// Verifies that GetNotificationForProperty returns Observable.Never for POCO types. - /// + /// Verifies that GetNotificationForProperty returns Observable.Never for POCO types. /// A task representing the asynchronous test operation. [Test] public async Task GetNotificationForProperty_PocoType_ReturnsNever() @@ -177,9 +152,7 @@ public async Task GetNotificationForProperty_PocoType_ReturnsNever() await Assert.That(emitted).IsFalse(); } - /// - /// Verifies that null or empty PropertyName in PropertyChanged emits for all listeners. - /// + /// Verifies that null or empty PropertyName in PropertyChanged emits for all listeners. /// A task representing the asynchronous test operation. [Test] public async Task GetNotificationForProperty_NullPropertyName_EmitsNotification() @@ -199,9 +172,7 @@ public async Task GetNotificationForProperty_NullPropertyName_EmitsNotification( await Assert.That(emitted).IsTrue(); } - /// - /// Verifies affinity is 0 for before-change on types without INotifyPropertyChanging. - /// + /// Verifies affinity is 0 for before-change on types without INotifyPropertyChanging. /// A task representing the asynchronous test operation. [Test] public async Task GetAffinityForObject_NonChangingType_Returns0ForBeforeChanged() @@ -213,9 +184,7 @@ public async Task GetAffinityForObject_NonChangingType_Returns0ForBeforeChanged( await Assert.That(affinity).IsEqualTo(0); } - /// - /// Verifies that GetNotificationForProperty emits for indexer property changes (PropertyChanged path). - /// + /// Verifies that GetNotificationForProperty emits for indexer property changes (PropertyChanged path). /// A task representing the asynchronous test operation. [Test] public async Task GetNotificationForProperty_IndexExpression_PropertyChanged_EmitsNotification() @@ -240,9 +209,7 @@ public async Task GetNotificationForProperty_IndexExpression_PropertyChanged_Emi await Assert.That(emitted).IsTrue(); } - /// - /// Verifies that GetNotificationForProperty emits for indexer property changes (PropertyChanging/beforeChanged path). - /// + /// Verifies that GetNotificationForProperty emits for indexer property changes (PropertyChanging/beforeChanged path). /// A task representing the asynchronous test operation. [Test] public async Task GetNotificationForProperty_IndexExpression_BeforeChanged_EmitsNotification() @@ -266,9 +233,7 @@ public async Task GetNotificationForProperty_IndexExpression_BeforeChanged_Emits await Assert.That(emitted).IsTrue(); } - /// - /// Verifies that indexer property notification does not emit for unrelated property name changes. - /// + /// Verifies that indexer property notification does not emit for unrelated property name changes. /// A task representing the asynchronous test operation. [Test] public async Task GetNotificationForProperty_IndexExpression_DifferentPropertyName_DoesNotEmit() @@ -292,9 +257,7 @@ public async Task GetNotificationForProperty_IndexExpression_DifferentPropertyNa await Assert.That(emitted).IsFalse(); } - /// - /// Verifies that indexer property notification emits when PropertyChanged fires with null/empty name. - /// + /// Verifies that indexer property notification emits when PropertyChanged fires with null/empty name. /// A task representing the asynchronous test operation. [Test] public async Task GetNotificationForProperty_IndexExpression_NullPropertyName_EmitsNotification() @@ -335,9 +298,7 @@ public async Task ObservableForProperty_ByName_InvalidProperty_StillCreatesObser await Assert.That(emitted).IsFalse(); } - /// - /// Verifies that ObservableForProperty by name with skipInitial=false emits the initial value. - /// + /// Verifies that ObservableForProperty by name with skipInitial=false emits the initial value. /// A task representing the asynchronous test operation. [Test] public async Task ObservableForProperty_ByName_SkipInitialFalse_EmitsInitialValue() @@ -351,9 +312,7 @@ public async Task ObservableForProperty_ByName_SkipInitialFalse_EmitsInitialValu await Assert.That(receivedValue).IsEqualTo("Initial"); } - /// - /// Verifies that ObservableForProperty by name with isDistinct=false allows duplicate values. - /// + /// Verifies that ObservableForProperty by name with isDistinct=false allows duplicate values. /// A task representing the asynchronous test operation. [Test] public async Task ObservableForProperty_ByName_IsDistinctFalse_AllowsDuplicates() @@ -599,78 +558,8 @@ public async Task PropertyChanging_EmptyPropertyName_MatchesAllProperties() await Assert.That(count).IsEqualTo(1); } - /// - /// A test model with a nullable property for testing null GetCurrentValue path. - /// - private sealed class NullablePropertyViewModel : INotifyPropertyChanged - { - /// - /// A private field representing a nullable string property used for testing - /// scenarios where the property's value may be null. - /// - private string? _nullableName; - - /// - public event PropertyChangedEventHandler? PropertyChanged; - - /// - /// Gets or sets the nullable name. - /// - public string? NullableName - { - get => _nullableName; - set - { - _nullableName = value; - PropertyChanged?.Invoke(this, new(nameof(NullableName))); - } - } - } - - /// - /// A test model that implements INotifyPropertyChanged but NOT INotifyPropertyChanging. - /// - [SuppressMessage( - "Performance", - "CA1812:Avoid uninstantiated internal classes", - Justification = "Referenced only via typeof metadata to assert affinity behavior; never constructed by design.")] - private sealed class NonChangingViewModel : INotifyPropertyChanged - { - /// -#pragma warning disable CS0067 // Event is never used - public event PropertyChangedEventHandler? PropertyChanged; -#pragma warning restore CS0067 - - /// - /// Gets or sets the name. - /// - public string Name { get; set; } = string.Empty; - } - - /// - /// A test model that raises PropertyChanged with null PropertyName. - /// - private sealed class NullPropertyNameViewModel : INotifyPropertyChanged - { - /// - public event PropertyChangedEventHandler? PropertyChanged; - - /// - /// Gets or sets the name. - /// - public string Name { get; set; } = string.Empty; - - /// - /// Raises PropertyChanged with null property name (all properties changed). - /// - public void RaiseAllPropertiesChanged() => - PropertyChanged?.Invoke(this, new(null)); - } - - /// - /// A test model with an indexer that implements both INotifyPropertyChanged and INotifyPropertyChanging. - /// - private sealed class IndexableViewModel : INotifyPropertyChanged, INotifyPropertyChanging + /// A test model with an indexer that implements both INotifyPropertyChanged and INotifyPropertyChanging. + public sealed class IndexableViewModel : INotifyPropertyChanged, INotifyPropertyChanging { /// /// A private dictionary field used to store key-value pairs for the indexer implementation @@ -685,14 +574,10 @@ private sealed class IndexableViewModel : INotifyPropertyChanged, INotifyPropert /// public event PropertyChangingEventHandler? PropertyChanging; - /// - /// Gets or sets a non-indexer property for testing non-Index expression paths. - /// + /// Gets or sets a non-indexer property for testing non-Index expression paths. public string SomeProp { get; set; } = string.Empty; - /// - /// Gets or sets the value associated with the specified key. - /// + /// Gets or sets the value associated with the specified key. /// The key of the value to get or set. /// The value associated with the specified key. public string this[string key] @@ -706,30 +591,67 @@ public string this[string key] } } - /// - /// Raises PropertyChanged with null property name (all properties changed). - /// + /// Raises PropertyChanged with null property name (all properties changed). public void RaiseAllPropertiesChanged() => PropertyChanged?.Invoke(this, new(null)); - /// - /// Raises PropertyChanged with a specific property name. - /// + /// Raises PropertyChanged with a specific property name. /// The property name to raise. public void RaisePropertyChangedWithName(string? propertyName) => PropertyChanged?.Invoke(this, new(propertyName)); - /// - /// Raises PropertyChanging with null property name (all properties changing). - /// + /// Raises PropertyChanging with null property name (all properties changing). public void RaiseAllPropertyChanging() => PropertyChanging?.Invoke(this, new(null)); - /// - /// Raises PropertyChanging with a specific property name. - /// + /// Raises PropertyChanging with a specific property name. /// The property name to raise. public void RaisePropertyChangingWithName(string? propertyName) => PropertyChanging?.Invoke(this, new(propertyName)); } + + /// A test model with a nullable property for testing null GetCurrentValue path. + private sealed class NullablePropertyViewModel : INotifyPropertyChanged + { + /// + public event PropertyChangedEventHandler? PropertyChanged; + + /// Gets or sets the nullable name. + [SuppressMessage("Design", "SST1440:Unused private member", Justification = "Resolved by name through the property observation path under test.")] + private string? NullableName + { + get => field; + set + { + field = value; + PropertyChanged?.Invoke(this, new(nameof(NullableName))); + } + } + } + + /// A test model that implements INotifyPropertyChanged but NOT INotifyPropertyChanging. + private sealed class NonChangingViewModel : INotifyPropertyChanged + { + /// +#pragma warning disable CS0067 // Event is never used + public event PropertyChangedEventHandler? PropertyChanged; +#pragma warning restore CS0067 + + /// Gets or sets the name. + public string Name { get; set; } = string.Empty; + } + + /// A test model that raises PropertyChanged with null PropertyName. + private sealed class NullPropertyNameViewModel : INotifyPropertyChanged + { + /// + public event PropertyChangedEventHandler? PropertyChanged; + + /// Gets or sets the name. + public string Name { get; set; } = string.Empty; + + /// Raises PropertyChanged with null property name (all properties changed). + public void RaiseAllPropertiesChanged() => + PropertyChanged?.Invoke(this, new(null)); + } } diff --git a/src/tests/ReactiveUI.Binding.Tests/ObservableForProperty/ObservedChangedMixinTests.cs b/src/tests/ReactiveUI.Binding.Tests/ObservableForProperty/ObservedChangedMixinTests.cs index 5ae5227..2d09c5f 100644 --- a/src/tests/ReactiveUI.Binding.Tests/ObservableForProperty/ObservedChangedMixinTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/ObservableForProperty/ObservedChangedMixinTests.cs @@ -8,29 +8,25 @@ namespace ReactiveUI.Binding.Tests.ObservableForProperty; -/// -/// Tests for the class. -/// +/// Tests for the class. public class ObservedChangedMixinTests { - /// - /// A directly-populated change value used across tests. - /// + /// The value assigned through the observed change under test. + private const string NewValue = "NewValue"; + + /// The age assigned to the sample view model. + private const int SampleAge = 42; + + /// A directly-populated change value used across tests. private const string DirectValue = "Direct"; - /// - /// A sample integer value carried by an observed change. - /// + /// A sample integer value carried by an observed change. private const int SampleIntValue = 99; - /// - /// The expected number of mapped values from a two-element change stream. - /// + /// The expected number of mapped values from a two-element change stream. private const int ExpectedTwoValues = 2; - /// - /// Verifies that GetPropertyName returns the correct property name from an observed change. - /// + /// Verifies that GetPropertyName returns the correct property name from an observed change. /// A task representing the asynchronous test operation. [Test] public async Task GetPropertyName_SimpleProperty_ReturnsName() @@ -45,9 +41,7 @@ public async Task GetPropertyName_SimpleProperty_ReturnsName() await Assert.That(name).IsEqualTo("Name"); } - /// - /// Verifies that GetPropertyName returns a dotted path for nested properties. - /// + /// Verifies that GetPropertyName returns a dotted path for nested properties. /// A task representing the asynchronous test operation. [Test] public async Task GetPropertyName_NestedProperty_ReturnsDottedPath() @@ -62,9 +56,7 @@ public async Task GetPropertyName_NestedProperty_ReturnsDottedPath() await Assert.That(name).IsEqualTo("Address.City"); } - /// - /// Verifies that GetValue returns the value when it's already populated. - /// + /// Verifies that GetValue returns the value when it's already populated. /// A task representing the asynchronous test operation. [Test] public async Task GetValue_WithPopulatedValue_ReturnsValue() @@ -79,9 +71,7 @@ public async Task GetValue_WithPopulatedValue_ReturnsValue() await Assert.That(value).IsEqualTo(DirectValue); } - /// - /// Verifies that GetValue evaluates the expression chain when value is default. - /// + /// Verifies that GetValue evaluates the expression chain when value is default. /// A task representing the asynchronous test operation. [Test] public async Task GetValue_WithDefaultValue_EvaluatesChain() @@ -97,9 +87,7 @@ public async Task GetValue_WithDefaultValue_EvaluatesChain() await Assert.That(value).IsEqualTo("Evaluated"); } - /// - /// Verifies that GetValueOrDefault returns default when chain is broken. - /// + /// Verifies that GetValueOrDefault returns default when chain is broken. /// A task representing the asynchronous test operation. [Test] public async Task GetValueOrDefault_NullInChain_ReturnsDefault() @@ -115,9 +103,7 @@ public async Task GetValueOrDefault_NullInChain_ReturnsDefault() await Assert.That(value).IsNull(); } - /// - /// Verifies that GetPropertyName throws for null input. - /// + /// Verifies that GetPropertyName throws for null input. /// A task representing the asynchronous test operation. [Test] public async Task GetPropertyName_NullItem_ThrowsArgumentNullException() @@ -128,9 +114,7 @@ await Assert.That(() => nullChange!.GetPropertyName()) .ThrowsExactly(); } - /// - /// Verifies that GetValue throws for null input. - /// + /// Verifies that GetValue throws for null input. /// A task representing the asynchronous test operation. [Test] public async Task GetValue_NullItem_ThrowsArgumentNullException() @@ -141,9 +125,7 @@ await Assert.That(() => nullChange!.GetValue()) .ThrowsExactly(); } - /// - /// Verifies that GetValueOrDefault throws for null input. - /// + /// Verifies that GetValueOrDefault throws for null input. /// A task representing the asynchronous test operation. [Test] public async Task GetValueOrDefault_NullItem_ThrowsArgumentNullException() @@ -154,9 +136,7 @@ await Assert.That(() => nullChange!.GetValueOrDefault()) .ThrowsExactly(); } - /// - /// Verifies that GetValue returns the populated value for a non-default value. - /// + /// Verifies that GetValue returns the populated value for a non-default value. /// A task representing the asynchronous test operation. [Test] public async Task GetValue_NonDefaultValue_ReturnsDirectValue() @@ -164,7 +144,7 @@ public async Task GetValue_NonDefaultValue_ReturnsDirectValue() Expression> expr = x => x.Age; var body = Reflection.Rewrite(expr.Body); - var vm = new TestViewModel { Age = 42 }; + var vm = new TestViewModel { Age = SampleAge }; var change = new ObservedChange(vm, body, SampleIntValue); var value = change.GetValue(); @@ -172,9 +152,7 @@ public async Task GetValue_NonDefaultValue_ReturnsDirectValue() await Assert.That(value).IsEqualTo(SampleIntValue); } - /// - /// Verifies that GetValueOrDefault returns the value when it's non-default. - /// + /// Verifies that GetValueOrDefault returns the value when it's non-default. /// A task representing the asynchronous test operation. [Test] public async Task GetValueOrDefault_WithNonDefaultValue_ReturnsValue() @@ -189,9 +167,7 @@ public async Task GetValueOrDefault_WithNonDefaultValue_ReturnsValue() await Assert.That(value).IsEqualTo(DirectValue); } - /// - /// Verifies that GetValue throws when the expression chain is broken (null intermediate). - /// + /// Verifies that GetValue throws when the expression chain is broken (null intermediate). /// A task representing the asynchronous test operation. [Test] public async Task GetValue_BrokenChain_ThrowsException() @@ -206,9 +182,7 @@ await Assert.That(() => change.GetValue()) .ThrowsExactly(); } - /// - /// Verifies that Value() observable extension maps a stream of changes to values. - /// + /// Verifies that Value() observable extension maps a stream of changes to values. /// A task representing the asynchronous test operation. [Test] public async Task Value_MapsChangesToValues() @@ -229,9 +203,7 @@ public async Task Value_MapsChangesToValues() await Assert.That(values[1]).IsEqualTo("Second"); } - /// - /// Verifies that SetValueToProperty applies the change to the target object. - /// + /// Verifies that SetValueToProperty applies the change to the target object. /// A task representing the asynchronous test operation. [Test] public async Task SetValueToProperty_ValidTarget_SetsValue() @@ -239,17 +211,15 @@ public async Task SetValueToProperty_ValidTarget_SetsValue() Expression> expr = x => x.Name; var body = Reflection.Rewrite(expr.Body); - var change = new ObservedChange(new(), body, "NewValue"); + var change = new ObservedChange(new(), body, NewValue); var target = new TestViewModel { Name = "OldValue" }; change.SetValueToProperty(target, x => x.Name); - await Assert.That(target.Name).IsEqualTo("NewValue"); + await Assert.That(target.Name).IsEqualTo(NewValue); } - /// - /// Verifies that SetValueToProperty does nothing when target is null. - /// + /// Verifies that SetValueToProperty does nothing when target is null. /// A task representing the asynchronous test operation. [Test] public async Task SetValueToProperty_NullTarget_DoesNotThrow() @@ -257,7 +227,7 @@ public async Task SetValueToProperty_NullTarget_DoesNotThrow() Expression> expr = x => x.Name; var body = Reflection.Rewrite(expr.Body); - var change = new ObservedChange(new(), body, "NewValue"); + var change = new ObservedChange(new(), body, NewValue); TestViewModel? target = null; // Should not throw diff --git a/src/tests/ReactiveUI.Binding.Tests/ObservableForProperty/POCOObservableForPropertyTests.cs b/src/tests/ReactiveUI.Binding.Tests/ObservableForProperty/POCOObservableForPropertyTests.cs index 6bc7d05..8cffaaa 100644 --- a/src/tests/ReactiveUI.Binding.Tests/ObservableForProperty/POCOObservableForPropertyTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/ObservableForProperty/POCOObservableForPropertyTests.cs @@ -8,28 +8,25 @@ namespace ReactiveUI.Binding.Tests.ObservableForProperty; -/// -/// Tests for the class. -/// +/// Tests for the class. public class POCOObservableForPropertyTests { - /// - /// Verifies affinity is always 1. - /// + /// The name of the property the POCO tests observe. + private const string ValuePropertyName = "Value"; + + /// Verifies affinity is always 1. /// A task representing the asynchronous test operation. [Test] public async Task GetAffinityForObject_AnyType_Returns1() { var sut = new POCOObservableForProperty(); - var affinity = sut.GetAffinityForObject(typeof(PocoModel), "Value"); + var affinity = sut.GetAffinityForObject(typeof(PocoModel), ValuePropertyName); await Assert.That(affinity).IsEqualTo(1); } - /// - /// Verifies affinity is 1 even for INPC types (POCO is the fallback). - /// + /// Verifies affinity is 1 even for INPC types (POCO is the fallback). /// A task representing the asynchronous test operation. [Test] public async Task GetAffinityForObject_INPCType_StillReturns1() @@ -41,9 +38,7 @@ public async Task GetAffinityForObject_INPCType_StillReturns1() await Assert.That(affinity).IsEqualTo(1); } - /// - /// Verifies that GetNotificationForProperty emits exactly one value on subscription. - /// + /// Verifies that GetNotificationForProperty emits exactly one value on subscription. /// A task representing the asynchronous test operation. [Test] public async Task GetNotificationForProperty_EmitsOneValue() @@ -55,16 +50,14 @@ public async Task GetNotificationForProperty_EmitsOneValue() var body = Reflection.Rewrite(expr.Body); var count = 0; - using var sub = sut.GetNotificationForProperty(model, body, "Value") + using var sub = sut.GetNotificationForProperty(model, body, ValuePropertyName) .Take(1) .Subscribe(_ => count++); await Assert.That(count).IsEqualTo(1); } - /// - /// Verifies that GetNotificationForProperty does not emit more than once even when property changes. - /// + /// Verifies that GetNotificationForProperty does not emit more than once even when property changes. /// A task representing the asynchronous test operation. [Test] public async Task GetNotificationForProperty_NoFurtherEmissions() @@ -76,7 +69,7 @@ public async Task GetNotificationForProperty_NoFurtherEmissions() var body = Reflection.Rewrite(expr.Body); var values = new List>(); - using var sub = sut.GetNotificationForProperty(model, body, "Value") + using var sub = sut.GetNotificationForProperty(model, body, ValuePropertyName) .Take(1) .Subscribe(values.Add); diff --git a/src/tests/ReactiveUI.Binding.Tests/ObservableForProperty/ReactiveNotifyPropertyChangedMixinTests.cs b/src/tests/ReactiveUI.Binding.Tests/ObservableForProperty/ReactiveNotifyPropertyChangedMixinTests.cs index 139e8c4..36e9738 100644 --- a/src/tests/ReactiveUI.Binding.Tests/ObservableForProperty/ReactiveNotifyPropertyChangedMixinTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/ObservableForProperty/ReactiveNotifyPropertyChangedMixinTests.cs @@ -10,30 +10,27 @@ namespace ReactiveUI.Binding.Tests.ObservableForProperty; /// -/// Tests for covering remaining branch gaps +/// Tests for covering remaining branch gaps /// including NestedObservedChanges, NotifyForProperty, and SubscribeToExpressionChain paths. /// public class ReactiveNotifyPropertyChangedMixinTests { - /// - /// A changed property value used across notification tests. - /// + /// The value the view model starts with. + private const string InitialValue = "Initial"; + + /// A changed property value used across notification tests. private const string ChangedValue = "Changed"; - /// - /// The expected number of emissions after a single change (kicker plus one change). - /// + /// The expected number of emissions after a single change (kicker plus one change). private const int ExpectedTwoEmissions = 2; - /// - /// The expected number of emissions after two successive changes (kicker plus two changes). - /// + /// The expected number of emissions after two successive changes (kicker plus two changes). private const int ExpectedThreeEmissions = 3; /// /// Verifies that NestedObservedChanges returns a single-element observable with default value /// when the sourceChange value is null. - /// Covers ReactiveNotifyPropertyChangedMixin.cs line 230-232 (sourceChange.Value is null branch). + /// Covers ReactiveNotifyPropertyChangedMixins.cs line 230-232 (sourceChange.Value is null branch). /// /// A task representing the asynchronous test operation. [Test] @@ -47,7 +44,7 @@ public async Task NestedObservedChanges_NullSourceChangeValue_ReturnsSingleKicke var sourceChange = new ObservedChange(null, body, null); var results = new List>(); - using var sub = ReactiveNotifyPropertyChangedMixin.NestedObservedChanges(body, sourceChange, false) + using var sub = ReactiveNotifyPropertyChangedMixins.NestedObservedChanges(body, sourceChange, false) .Subscribe(results.Add); await Assert.That(results.Count).IsEqualTo(1); @@ -57,7 +54,7 @@ public async Task NestedObservedChanges_NullSourceChangeValue_ReturnsSingleKicke /// /// Verifies that NestedObservedChanges emits a kicker followed by property notifications /// when the sourceChange value is non-null. - /// Covers ReactiveNotifyPropertyChangedMixin.cs line 235-237 (sourceChange.Value is not null branch). + /// Covers ReactiveNotifyPropertyChangedMixins.cs line 235-237 (sourceChange.Value is not null branch). /// /// A task representing the asynchronous test operation. [Test] @@ -65,7 +62,7 @@ public async Task NestedObservedChanges_NonNullSourceChangeValue_EmitsKickerAndN { EnsureInitialized(); - var vm = new TestViewModel { Name = "Initial" }; + var vm = new TestViewModel { Name = InitialValue }; Expression> expr = x => x.Name; var body = Reflection.Rewrite(expr.Body); @@ -73,7 +70,7 @@ public async Task NestedObservedChanges_NonNullSourceChangeValue_EmitsKickerAndN var sourceChange = new ObservedChange(null, body, vm); var results = new List>(); - using var sub = ReactiveNotifyPropertyChangedMixin.NestedObservedChanges(body, sourceChange, false) + using var sub = ReactiveNotifyPropertyChangedMixins.NestedObservedChanges(body, sourceChange, false) .Subscribe(results.Add); // Should have the kicker (StartWith) @@ -87,7 +84,7 @@ public async Task NestedObservedChanges_NonNullSourceChangeValue_EmitsKickerAndN /// /// Verifies that NotifyForProperty throws ArgumentException when the expression has no valid member info. - /// Covers ReactiveNotifyPropertyChangedMixin.cs line 248 (memberInfo null branch). + /// Covers ReactiveNotifyPropertyChangedMixins.cs line 248 (memberInfo null branch). /// /// A task representing the asynchronous test operation. [Test] @@ -100,7 +97,7 @@ public async Task NotifyForProperty_ExpressionWithNoMemberInfo_ThrowsArgumentExc // A ParameterExpression has no member info, so GetMemberInfo will throw var paramExpr = System.Linq.Expressions.Expression.Parameter(typeof(TestViewModel), "x"); - var action = () => ReactiveNotifyPropertyChangedMixin.NotifyForProperty(vm, paramExpr, false); + var action = () => ReactiveNotifyPropertyChangedMixins.NotifyForProperty(vm, paramExpr, false); await Assert.That(action).ThrowsException(); } @@ -108,7 +105,7 @@ public async Task NotifyForProperty_ExpressionWithNoMemberInfo_ThrowsArgumentExc /// /// Verifies that SubscribeToExpressionChain with isDistinct=false does not deduplicate values /// when the same value is emitted multiple times. - /// Covers ReactiveNotifyPropertyChangedMixin.cs line 219 (isDistinct false branch in expression chain overload). + /// Covers ReactiveNotifyPropertyChangedMixins.cs line 219 (isDistinct false branch in expression chain overload). /// /// A task representing the asynchronous test operation. [Test] @@ -137,7 +134,7 @@ public async Task SubscribeToExpressionChain_IsDistinctFalse_DoesNotDeduplicate( /// /// Verifies that SubscribeToExpressionChain with isDistinct=true deduplicates by value. - /// Covers ReactiveNotifyPropertyChangedMixin.cs line 219 (isDistinct true branch in expression chain overload). + /// Covers ReactiveNotifyPropertyChangedMixins.cs line 219 (isDistinct true branch in expression chain overload). /// /// A task representing the asynchronous test operation. [Test] @@ -167,7 +164,7 @@ public async Task SubscribeToExpressionChain_IsDistinctTrue_DeduplicatesByValue( /// /// Verifies that SubscribeToExpressionChain with skipInitial=true skips the first value. - /// Covers ReactiveNotifyPropertyChangedMixin.cs line 201-203 (skipInitial true path). + /// Covers ReactiveNotifyPropertyChangedMixins.cs line 201-203 (skipInitial true path). /// /// A task representing the asynchronous test operation. [Test] @@ -175,7 +172,7 @@ public async Task SubscribeToExpressionChain_SkipInitialTrue_SkipsFirstValue() { EnsureInitialized(); - var fixture = new TestFixture { IsNotNullString = "Initial" }; + var fixture = new TestFixture { IsNotNullString = InitialValue }; Expression> expr = x => x.IsNotNullString; @@ -198,7 +195,7 @@ public async Task SubscribeToExpressionChain_SkipInitialTrue_SkipsFirstValue() /// /// Verifies that SubscribeToExpressionChain filters out null senders from the chain. - /// Covers ReactiveNotifyPropertyChangedMixin.cs line 206 (Where x.Sender is not null filter). + /// Covers ReactiveNotifyPropertyChangedMixins.cs line 206 (Where x.Sender is not null filter). /// /// A task representing the asynchronous test operation. [Test] @@ -230,7 +227,7 @@ public async Task SubscribeToExpressionChain_NullSenderInChain_IsFilteredOut() /// /// Verifies that ObservableForProperty by name with beforeChange=true emits before-change notifications. - /// Covers ReactiveNotifyPropertyChangedMixin.cs line 111-129 (factory subscription path with beforeChange). + /// Covers ReactiveNotifyPropertyChangedMixins.cs line 111-129 (factory subscription path with beforeChange). /// /// A task representing the asynchronous test operation. [Test] @@ -273,7 +270,7 @@ public async Task ObservableForProperty_ByExpression_BeforeChange_EmitsNotificat /// /// Verifies that NestedObservedChanges with beforeChange=true routes through /// the PropertyChanging event path. - /// Covers ReactiveNotifyPropertyChangedMixin.cs line 235 with beforeChange true. + /// Covers ReactiveNotifyPropertyChangedMixins.cs line 235 with beforeChange true. /// /// A task representing the asynchronous test operation. [Test] @@ -281,7 +278,7 @@ public async Task NestedObservedChanges_BeforeChange_RoutesToPropertyChanging() { EnsureInitialized(); - var vm = new TestViewModel { Name = "Initial" }; + var vm = new TestViewModel { Name = InitialValue }; Expression> expr = x => x.Name; var body = Reflection.Rewrite(expr.Body); @@ -289,7 +286,7 @@ public async Task NestedObservedChanges_BeforeChange_RoutesToPropertyChanging() var sourceChange = new ObservedChange(null, body, vm); var results = new List>(); - using var sub = ReactiveNotifyPropertyChangedMixin.NestedObservedChanges(body, sourceChange, true) + using var sub = ReactiveNotifyPropertyChangedMixins.NestedObservedChanges(body, sourceChange, true) .Subscribe(results.Add); // Should have the kicker from StartWith @@ -304,7 +301,7 @@ public async Task NestedObservedChanges_BeforeChange_RoutesToPropertyChanging() /// /// Verifies that the val cast path in SubscribeToExpressionChain line 93 is exercised /// when val is TValue (the normal case). - /// Covers ReactiveNotifyPropertyChangedMixin.cs line 93 (val is TValue cast). + /// Covers ReactiveNotifyPropertyChangedMixins.cs line 93 (val is TValue cast). /// /// A task representing the asynchronous test operation. [Test] @@ -321,14 +318,12 @@ public async Task ObservableForProperty_ByName_GetCurrentValue_ValIsTValue_Succe await Assert.That(receivedValue).IsEqualTo("Test"); } - /// - /// Resets and initializes the ReactiveUI binding infrastructure for testing. - /// + /// Resets and initializes the ReactiveUI binding infrastructure for testing. private static void EnsureInitialized() { RxBindingBuilder.ResetForTesting(); var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - builder.WithCoreServices(); - builder.BuildApp(); + _ = builder.WithCoreServices(); + _ = builder.BuildApp(); } } diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/ActionDisposableTests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/ActionDisposableTests.cs index 6bf300d..d70d972 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/ActionDisposableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/ActionDisposableTests.cs @@ -6,14 +6,10 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Tests for the class which invokes an action on disposal. -/// +/// Tests for the class which invokes an action on disposal. public class ActionDisposableTests { - /// - /// Verifies that the action is invoked when Dispose is called. - /// + /// Verifies that the action is invoked when Dispose is called. /// A task representing the asynchronous operation. [Test] public async Task Dispose_InvokesAction() @@ -26,9 +22,7 @@ public async Task Dispose_InvokesAction() await Assert.That(invoked).IsTrue(); } - /// - /// Verifies that the action is invoked only once even if Dispose is called multiple times. - /// + /// Verifies that the action is invoked only once even if Dispose is called multiple times. /// A task representing the asynchronous operation. [Test] public async Task Dispose_CalledTwice_InvokesActionOnlyOnce() @@ -42,10 +36,8 @@ public async Task Dispose_CalledTwice_InvokesActionOnlyOnce() await Assert.That(invokeCount).IsEqualTo(1); } - /// - /// Verifies that constructor throws ArgumentNullException when action is null. - /// + /// Verifies that constructor throws ArgumentNullException when action is null. [Test] public void Constructor_NullAction_ThrowsArgumentNullException() => - Assert.Throws(() => _ = new ActionDisposable(null!)); + Assert.Throws(static () => _ = new ActionDisposable(null!)); } diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest10ObservableTests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest10ObservableTests.cs index 547f2f0..50628c9 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest10ObservableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest10ObservableTests.cs @@ -8,123 +8,75 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Unit tests for edge cases. -/// +/// Unit tests for edge cases. public class CombineLatest10ObservableTests { - /// - /// The exception message used for errors that the subscription is expected to ignore. - /// + /// The exception message used for errors that the subscription is expected to ignore. private const string IgnoredErrorMessage = "should be ignored"; - /// - /// The distinct sample value emitted from the second source during a combination sequence. - /// + /// The distinct sample value emitted from the second source during a combination sequence. private const int Source2Value = 2; - /// - /// The distinct sample value emitted from the third source during a combination sequence. - /// + /// The distinct sample value emitted from the third source during a combination sequence. private const int Source3Value = 3; - /// - /// The distinct sample value emitted from the fourth source during a combination sequence. - /// + /// The distinct sample value emitted from the fourth source during a combination sequence. private const int Source4Value = 4; - /// - /// The distinct sample value emitted from the fifth source during a combination sequence. - /// + /// The distinct sample value emitted from the fifth source during a combination sequence. private const int Source5Value = 5; - /// - /// The distinct sample value emitted from the sixth source during a combination sequence. - /// + /// The distinct sample value emitted from the sixth source during a combination sequence. private const int Source6Value = 6; - /// - /// The distinct sample value emitted from the seventh source during a combination sequence. - /// + /// The distinct sample value emitted from the seventh source during a combination sequence. private const int Source7Value = 7; - /// - /// The distinct sample value emitted from the eighth source during a combination sequence. - /// + /// The distinct sample value emitted from the eighth source during a combination sequence. private const int Source8Value = 8; - /// - /// The distinct sample value emitted from the ninth source during a combination sequence. - /// + /// The distinct sample value emitted from the ninth source during a combination sequence. private const int Source9Value = 9; - /// - /// The distinct sample value emitted from the tenth source during a combination sequence. - /// + /// The distinct sample value emitted from the tenth source during a combination sequence. private const int Source10Value = 10; - /// - /// The value emitted from the first source after the subscription has been disposed. - /// + /// The value emitted from the first source after the subscription has been disposed. private const int Source1ValueAfterDispose = 10; - /// - /// The value emitted from the second source after the subscription has been disposed. - /// + /// The value emitted from the second source after the subscription has been disposed. private const int Source2ValueAfterDispose = 20; - /// - /// The value emitted from the third source after the subscription has been disposed. - /// + /// The value emitted from the third source after the subscription has been disposed. private const int Source3ValueAfterDispose = 30; - /// - /// The value emitted from the fourth source after the subscription has been disposed. - /// + /// The value emitted from the fourth source after the subscription has been disposed. private const int Source4ValueAfterDispose = 40; - /// - /// The value emitted from the fifth source after the subscription has been disposed. - /// + /// The value emitted from the fifth source after the subscription has been disposed. private const int Source5ValueAfterDispose = 50; - /// - /// The value emitted from the sixth source after the subscription has been disposed. - /// + /// The value emitted from the sixth source after the subscription has been disposed. private const int Source6ValueAfterDispose = 60; - /// - /// The value emitted from the seventh source after the subscription has been disposed. - /// + /// The value emitted from the seventh source after the subscription has been disposed. private const int Source7ValueAfterDispose = 70; - /// - /// The value emitted from the eighth source after the subscription has been disposed. - /// + /// The value emitted from the eighth source after the subscription has been disposed. private const int Source8ValueAfterDispose = 80; - /// - /// The value emitted from the ninth source after the subscription has been disposed. - /// + /// The value emitted from the ninth source after the subscription has been disposed. private const int Source9ValueAfterDispose = 90; - /// - /// The value emitted from the tenth source after the subscription has been disposed. - /// + /// The value emitted from the tenth source after the subscription has been disposed. private const int Source10ValueAfterDispose = 100; - /// - /// Verifies that a null first source throws . - /// + /// Verifies that a null first source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource1_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( (IObservable)null!, new Subject(), new Subject(), @@ -135,23 +87,17 @@ public async Task Constructor_NullSource1_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); + static (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null second source throws . - /// + /// Verifies that a null second source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource2_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), (IObservable)null!, new Subject(), @@ -162,23 +108,17 @@ public async Task Constructor_NullSource2_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); + static (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null third source throws . - /// + /// Verifies that a null third source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource3_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), (IObservable)null!, @@ -189,23 +129,17 @@ public async Task Constructor_NullSource3_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); + static (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fourth source throws . - /// + /// Verifies that a null fourth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource4_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -216,23 +150,17 @@ public async Task Constructor_NullSource4_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); + static (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fifth source throws . - /// + /// Verifies that a null fifth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource5_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -243,23 +171,17 @@ public async Task Constructor_NullSource5_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); + static (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null sixth source throws . - /// + /// Verifies that a null sixth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource6_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -270,23 +192,17 @@ public async Task Constructor_NullSource6_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); + static (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null seventh source throws . - /// + /// Verifies that a null seventh source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource7_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -297,23 +213,17 @@ public async Task Constructor_NullSource7_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); + static (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null eighth source throws . - /// + /// Verifies that a null eighth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource8_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -324,23 +234,17 @@ public async Task Constructor_NullSource8_Throws() (IObservable)null!, new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); + static (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null ninth source throws . - /// + /// Verifies that a null ninth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource9_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -351,23 +255,17 @@ public async Task Constructor_NullSource9_Throws() new Subject(), (IObservable)null!, new Subject(), - (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); + static (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null tenth source throws . - /// + /// Verifies that a null tenth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource10_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -378,19 +276,17 @@ public async Task Constructor_NullSource10_Throws() new Subject(), new Subject(), (IObservable)null!, - (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); + static (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null result selector throws . - /// + /// Verifies that a null result selector throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullResultSelector_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -406,14 +302,8 @@ public async Task Constructor_NullResultSelector_Throws() await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that subscribing with a null observer throws . - /// + /// Verifies that subscribing with a null observer throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Subscribe_NullObserver_Throws() { @@ -428,21 +318,15 @@ public async Task Subscribe_NullObserver_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); + static (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); var act = () => combined.Subscribe(null!); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that disposing twice does not throw an exception. - /// + /// Verifies that disposing twice does not throw an exception. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Dispose_CalledTwice_NoException() { @@ -457,23 +341,17 @@ public async Task Dispose_CalledTwice_NoException() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); + static (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); - var subscription = combined.Subscribe(new AnonymousObserver(_ => { }, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(static _ => { }, static _ => { }, static () => { })); subscription.Dispose(); subscription.Dispose(); await Assert.That(subscription.GetType()).IsNotNull(); } - /// - /// Verifies that a source emitting after dispose does not throw. - /// + /// Verifies that a source emitting after dispose does not throw. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task SourceEmitsAfterDispose_NoException() { @@ -498,10 +376,10 @@ public async Task SourceEmitsAfterDispose_NoException() source8, source9, source10, - (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); + static (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); var results = new List(); - var subscription = combined.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); source1.OnNext(1); source2.OnNext(1); @@ -520,14 +398,8 @@ public async Task SourceEmitsAfterDispose_NoException() await Assert.That(results).Count().IsEqualTo(1); } - /// - /// Verifies that an error after dispose is ignored. - /// + /// Verifies that an error after dispose is ignored. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorAfterDispose_IsIgnored() { @@ -552,13 +424,13 @@ public async Task ErrorAfterDispose_IsIgnored() source8, source9, source10, - (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); + static (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); subscription.Dispose(); source1.OnError(new InvalidOperationException(IgnoredErrorMessage)); @@ -580,10 +452,7 @@ public async Task ErrorAfterDispose_IsIgnored() /// when the subscription has been disposed but the observers are still reachable. /// /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] + [SuppressMessage("Design", "SST1523:Methods should not be too long", Justification = "Length is intrinsic to the fixed CombineLatest arity; each source needs its own line.")] [Test] public async Task ErrorAfterDispose_AllObservers_CoverNullPath() { @@ -608,13 +477,13 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() manual8, manual9, manual10, - (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); + static (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j); Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); // Set all has-value flags so TryEmit reaches _observer?.OnNext manual1.Observer!.OnNext(1); @@ -655,14 +524,8 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() await Assert.That(receivedError).IsNull(); } - /// - /// Verifies that an error in the first source observable is propagated to the subscriber. - /// + /// Verifies that an error in the first source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource1_PropagatedToSubscriber() { @@ -687,15 +550,15 @@ public async Task ErrorInSource1_PropagatedToSubscriber() source8, source9, source10, - (a, b, c, d, e, f, g, h, i, j) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}"); + static (a, b, c, d, e, f, g, h, i, j) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source1 error"); source1.OnError(expectedError); @@ -705,14 +568,8 @@ public async Task ErrorInSource1_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the second source observable is propagated to the subscriber. - /// + /// Verifies that an error in the second source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource2_PropagatedToSubscriber() { @@ -737,15 +594,15 @@ public async Task ErrorInSource2_PropagatedToSubscriber() source8, source9, source10, - (a, b, c, d, e, f, g, h, i, j) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}"); + static (a, b, c, d, e, f, g, h, i, j) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source2 error"); source2.OnError(expectedError); @@ -755,14 +612,8 @@ public async Task ErrorInSource2_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the third source observable is propagated to the subscriber. - /// + /// Verifies that an error in the third source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource3_PropagatedToSubscriber() { @@ -787,15 +638,15 @@ public async Task ErrorInSource3_PropagatedToSubscriber() source8, source9, source10, - (a, b, c, d, e, f, g, h, i, j) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}"); + static (a, b, c, d, e, f, g, h, i, j) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source3 error"); source3.OnError(expectedError); @@ -805,14 +656,8 @@ public async Task ErrorInSource3_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fourth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fourth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource4_PropagatedToSubscriber() { @@ -837,15 +682,15 @@ public async Task ErrorInSource4_PropagatedToSubscriber() source8, source9, source10, - (a, b, c, d, e, f, g, h, i, j) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}"); + static (a, b, c, d, e, f, g, h, i, j) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source4 error"); source4.OnError(expectedError); @@ -855,14 +700,8 @@ public async Task ErrorInSource4_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fifth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fifth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource5_PropagatedToSubscriber() { @@ -887,15 +726,15 @@ public async Task ErrorInSource5_PropagatedToSubscriber() source8, source9, source10, - (a, b, c, d, e, f, g, h, i, j) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}"); + static (a, b, c, d, e, f, g, h, i, j) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source5 error"); source5.OnError(expectedError); @@ -905,14 +744,8 @@ public async Task ErrorInSource5_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the sixth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the sixth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource6_PropagatedToSubscriber() { @@ -937,15 +770,15 @@ public async Task ErrorInSource6_PropagatedToSubscriber() source8, source9, source10, - (a, b, c, d, e, f, g, h, i, j) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}"); + static (a, b, c, d, e, f, g, h, i, j) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source6 error"); source6.OnError(expectedError); @@ -955,14 +788,8 @@ public async Task ErrorInSource6_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the seventh source observable is propagated to the subscriber. - /// + /// Verifies that an error in the seventh source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource7_PropagatedToSubscriber() { @@ -987,15 +814,15 @@ public async Task ErrorInSource7_PropagatedToSubscriber() source8, source9, source10, - (a, b, c, d, e, f, g, h, i, j) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}"); + static (a, b, c, d, e, f, g, h, i, j) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source7 error"); source7.OnError(expectedError); @@ -1005,14 +832,8 @@ public async Task ErrorInSource7_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the eighth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the eighth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource8_PropagatedToSubscriber() { @@ -1037,15 +858,15 @@ public async Task ErrorInSource8_PropagatedToSubscriber() source8, source9, source10, - (a, b, c, d, e, f, g, h, i, j) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}"); + static (a, b, c, d, e, f, g, h, i, j) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source8 error"); source8.OnError(expectedError); @@ -1055,14 +876,8 @@ public async Task ErrorInSource8_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the ninth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the ninth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource9_PropagatedToSubscriber() { @@ -1087,15 +902,15 @@ public async Task ErrorInSource9_PropagatedToSubscriber() source8, source9, source10, - (a, b, c, d, e, f, g, h, i, j) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}"); + static (a, b, c, d, e, f, g, h, i, j) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source9 error"); source9.OnError(expectedError); @@ -1105,14 +920,8 @@ public async Task ErrorInSource9_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the tenth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the tenth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource10_PropagatedToSubscriber() { @@ -1137,15 +946,15 @@ public async Task ErrorInSource10_PropagatedToSubscriber() source8, source9, source10, - (a, b, c, d, e, f, g, h, i, j) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}"); + static (a, b, c, d, e, f, g, h, i, j) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source10 error"); source10.OnError(expectedError); @@ -1155,14 +964,8 @@ public async Task ErrorInSource10_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that OnCompleted from a single source does not propagate completion. - /// + /// Verifies that OnCompleted from a single source does not propagate completion. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task CompletedInSource_DoesNotPropagateCompletion() { @@ -1187,14 +990,14 @@ public async Task CompletedInSource_DoesNotPropagateCompletion() source8, source9, source10, - (a, b, c, d, e, f, g, h, i, j) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}"); + static (a, b, c, d, e, f, g, h, i, j) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}"); var completed = false; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, - _ => { }, + static _ => { }, () => completed = true)); source1.OnNext(1); @@ -1223,15 +1026,12 @@ public async Task CompletedInSource_DoesNotPropagateCompletion() await Assert.That(results).Count().IsEqualTo(1); } - /// - /// A simple observer implementation that delegates to provided action callbacks. - /// + /// A simple observer implementation that delegates to provided action callbacks. /// The type of elements observed. /// The action to invoke for each observed element. /// The action to invoke when an error occurs. /// The action to invoke when the sequence completes. - private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) - : IObserver + private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) : IObserver { /// public void OnCompleted() => onCompleted(); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest11ObservableTests.Disposal.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest11ObservableTests.Disposal.cs index 4cc421e..c34d7ec 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest11ObservableTests.Disposal.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest11ObservableTests.Disposal.cs @@ -8,19 +8,11 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Tests for CombineLatest with 11 sources — disposal, post-dispose, and completion behavior. -/// +/// Tests for CombineLatest with 11 sources — disposal, post-dispose, and completion behavior. public partial class CombineLatest11ObservableTests { - /// - /// Verifies that disposing twice does not throw an exception. - /// + /// Verifies that disposing twice does not throw an exception. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Dispose_CalledTwice_NoException() { @@ -36,23 +28,17 @@ public async Task Dispose_CalledTwice_NoException() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); + static (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); - var subscription = combined.Subscribe(new AnonymousObserver(_ => { }, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(static _ => { }, static _ => { }, static () => { })); subscription.Dispose(); subscription.Dispose(); await Assert.That(subscription.GetType()).IsNotNull(); } - /// - /// Verifies that a source emitting after dispose does not throw. - /// + /// Verifies that a source emitting after dispose does not throw. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task SourceEmitsAfterDispose_NoException() { @@ -79,10 +65,10 @@ public async Task SourceEmitsAfterDispose_NoException() source9, source10, source11, - (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); + static (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); var results = new List(); - var subscription = combined.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); source1.OnNext(1); source2.OnNext(1); @@ -102,14 +88,8 @@ public async Task SourceEmitsAfterDispose_NoException() await Assert.That(results).Count().IsEqualTo(1); } - /// - /// Verifies that an error after dispose is ignored. - /// + /// Verifies that an error after dispose is ignored. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorAfterDispose_IsIgnored() { @@ -136,13 +116,13 @@ public async Task ErrorAfterDispose_IsIgnored() source9, source10, source11, - (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); + static (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); subscription.Dispose(); source1.OnError(new InvalidOperationException(IgnoredErrorMessage)); @@ -165,10 +145,7 @@ public async Task ErrorAfterDispose_IsIgnored() /// when the subscription has been disposed but the observers are still reachable. /// /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] + [SuppressMessage("Design", "SST1523:Methods should not be too long", Justification = "Length is intrinsic to the fixed CombineLatest arity; each source needs its own line.")] [Test] public async Task ErrorAfterDispose_AllObservers_CoverNullPath() { @@ -195,13 +172,13 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() manual9, manual10, manual11, - (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); + static (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); // Set all has-value flags so TryEmit reaches _observer?.OnNext manual1.Observer!.OnNext(1); @@ -245,14 +222,8 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() await Assert.That(receivedError).IsNull(); } - /// - /// Verifies that OnCompleted from a single source does not propagate completion. - /// + /// Verifies that OnCompleted from a single source does not propagate completion. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task CompletedInSource_DoesNotPropagateCompletion() { @@ -279,14 +250,14 @@ public async Task CompletedInSource_DoesNotPropagateCompletion() source9, source10, source11, - (a, b, c, d, e, f, g, h, i, j, k) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}"); + static (a, b, c, d, e, f, g, h, i, j, k) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}"); var completed = false; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, - _ => { }, + static _ => { }, () => completed = true)); source1.OnNext(1); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest11ObservableTests.Emission.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest11ObservableTests.Emission.cs index 1a7ac88..328ffe0 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest11ObservableTests.Emission.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest11ObservableTests.Emission.cs @@ -7,19 +7,11 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Tests for CombineLatest with 11 sources — per-source error propagation. -/// +/// Tests for CombineLatest with 11 sources — per-source error propagation. public partial class CombineLatest11ObservableTests { - /// - /// Verifies that an error in the first source observable is propagated to the subscriber. - /// + /// Verifies that an error in the first source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource1_PropagatedToSubscriber() { @@ -46,15 +38,15 @@ public async Task ErrorInSource1_PropagatedToSubscriber() source9, source10, source11, - (a, b, c, d, e, f, g, h, i, j, k) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}"); + static (a, b, c, d, e, f, g, h, i, j, k) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source1 error"); source1.OnError(expectedError); @@ -64,14 +56,8 @@ public async Task ErrorInSource1_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the second source observable is propagated to the subscriber. - /// + /// Verifies that an error in the second source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource2_PropagatedToSubscriber() { @@ -98,15 +84,15 @@ public async Task ErrorInSource2_PropagatedToSubscriber() source9, source10, source11, - (a, b, c, d, e, f, g, h, i, j, k) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}"); + static (a, b, c, d, e, f, g, h, i, j, k) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source2 error"); source2.OnError(expectedError); @@ -116,14 +102,8 @@ public async Task ErrorInSource2_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the third source observable is propagated to the subscriber. - /// + /// Verifies that an error in the third source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource3_PropagatedToSubscriber() { @@ -150,15 +130,15 @@ public async Task ErrorInSource3_PropagatedToSubscriber() source9, source10, source11, - (a, b, c, d, e, f, g, h, i, j, k) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}"); + static (a, b, c, d, e, f, g, h, i, j, k) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source3 error"); source3.OnError(expectedError); @@ -168,14 +148,8 @@ public async Task ErrorInSource3_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fourth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fourth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource4_PropagatedToSubscriber() { @@ -202,15 +176,15 @@ public async Task ErrorInSource4_PropagatedToSubscriber() source9, source10, source11, - (a, b, c, d, e, f, g, h, i, j, k) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}"); + static (a, b, c, d, e, f, g, h, i, j, k) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source4 error"); source4.OnError(expectedError); @@ -220,14 +194,8 @@ public async Task ErrorInSource4_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fifth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fifth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource5_PropagatedToSubscriber() { @@ -254,15 +222,15 @@ public async Task ErrorInSource5_PropagatedToSubscriber() source9, source10, source11, - (a, b, c, d, e, f, g, h, i, j, k) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}"); + static (a, b, c, d, e, f, g, h, i, j, k) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source5 error"); source5.OnError(expectedError); @@ -272,14 +240,8 @@ public async Task ErrorInSource5_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the sixth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the sixth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource6_PropagatedToSubscriber() { @@ -306,15 +268,15 @@ public async Task ErrorInSource6_PropagatedToSubscriber() source9, source10, source11, - (a, b, c, d, e, f, g, h, i, j, k) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}"); + static (a, b, c, d, e, f, g, h, i, j, k) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source6 error"); source6.OnError(expectedError); @@ -324,14 +286,8 @@ public async Task ErrorInSource6_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the seventh source observable is propagated to the subscriber. - /// + /// Verifies that an error in the seventh source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource7_PropagatedToSubscriber() { @@ -358,15 +314,15 @@ public async Task ErrorInSource7_PropagatedToSubscriber() source9, source10, source11, - (a, b, c, d, e, f, g, h, i, j, k) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}"); + static (a, b, c, d, e, f, g, h, i, j, k) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source7 error"); source7.OnError(expectedError); @@ -376,14 +332,8 @@ public async Task ErrorInSource7_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the eighth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the eighth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource8_PropagatedToSubscriber() { @@ -410,15 +360,15 @@ public async Task ErrorInSource8_PropagatedToSubscriber() source9, source10, source11, - (a, b, c, d, e, f, g, h, i, j, k) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}"); + static (a, b, c, d, e, f, g, h, i, j, k) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source8 error"); source8.OnError(expectedError); @@ -428,14 +378,8 @@ public async Task ErrorInSource8_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the ninth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the ninth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource9_PropagatedToSubscriber() { @@ -462,15 +406,15 @@ public async Task ErrorInSource9_PropagatedToSubscriber() source9, source10, source11, - (a, b, c, d, e, f, g, h, i, j, k) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}"); + static (a, b, c, d, e, f, g, h, i, j, k) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source9 error"); source9.OnError(expectedError); @@ -480,14 +424,8 @@ public async Task ErrorInSource9_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the tenth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the tenth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource10_PropagatedToSubscriber() { @@ -514,15 +452,15 @@ public async Task ErrorInSource10_PropagatedToSubscriber() source9, source10, source11, - (a, b, c, d, e, f, g, h, i, j, k) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}"); + static (a, b, c, d, e, f, g, h, i, j, k) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source10 error"); source10.OnError(expectedError); @@ -532,14 +470,8 @@ public async Task ErrorInSource10_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the eleventh source observable is propagated to the subscriber. - /// + /// Verifies that an error in the eleventh source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource11_PropagatedToSubscriber() { @@ -566,15 +498,15 @@ public async Task ErrorInSource11_PropagatedToSubscriber() source9, source10, source11, - (a, b, c, d, e, f, g, h, i, j, k) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}"); + static (a, b, c, d, e, f, g, h, i, j, k) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source11 error"); source11.OnError(expectedError); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest11ObservableTests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest11ObservableTests.cs index ef249b7..3e57c0b 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest11ObservableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest11ObservableTests.cs @@ -7,133 +7,81 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Unit tests for edge cases. -/// +/// Unit tests for edge cases. public partial class CombineLatest11ObservableTests { - /// - /// The exception message used for errors that the subscription is expected to ignore. - /// + /// The exception message used for errors that the subscription is expected to ignore. private const string IgnoredErrorMessage = "should be ignored"; - /// - /// The distinct sample value emitted from the second source during a combination sequence. - /// + /// The distinct sample value emitted from the second source during a combination sequence. private const int Source2Value = 2; - /// - /// The distinct sample value emitted from the third source during a combination sequence. - /// + /// The distinct sample value emitted from the third source during a combination sequence. private const int Source3Value = 3; - /// - /// The distinct sample value emitted from the fourth source during a combination sequence. - /// + /// The distinct sample value emitted from the fourth source during a combination sequence. private const int Source4Value = 4; - /// - /// The distinct sample value emitted from the fifth source during a combination sequence. - /// + /// The distinct sample value emitted from the fifth source during a combination sequence. private const int Source5Value = 5; - /// - /// The distinct sample value emitted from the sixth source during a combination sequence. - /// + /// The distinct sample value emitted from the sixth source during a combination sequence. private const int Source6Value = 6; - /// - /// The distinct sample value emitted from the seventh source during a combination sequence. - /// + /// The distinct sample value emitted from the seventh source during a combination sequence. private const int Source7Value = 7; - /// - /// The distinct sample value emitted from the eighth source during a combination sequence. - /// + /// The distinct sample value emitted from the eighth source during a combination sequence. private const int Source8Value = 8; - /// - /// The distinct sample value emitted from the ninth source during a combination sequence. - /// + /// The distinct sample value emitted from the ninth source during a combination sequence. private const int Source9Value = 9; - /// - /// The distinct sample value emitted from the tenth source during a combination sequence. - /// + /// The distinct sample value emitted from the tenth source during a combination sequence. private const int Source10Value = 10; - /// - /// The distinct sample value emitted from the eleventh source during a combination sequence. - /// + /// The distinct sample value emitted from the eleventh source during a combination sequence. private const int Source11Value = 11; - /// - /// The value emitted from the first source after the subscription has been disposed. - /// + /// The value emitted from the first source after the subscription has been disposed. private const int Source1ValueAfterDispose = 10; - /// - /// The value emitted from the second source after the subscription has been disposed. - /// + /// The value emitted from the second source after the subscription has been disposed. private const int Source2ValueAfterDispose = 20; - /// - /// The value emitted from the third source after the subscription has been disposed. - /// + /// The value emitted from the third source after the subscription has been disposed. private const int Source3ValueAfterDispose = 30; - /// - /// The value emitted from the fourth source after the subscription has been disposed. - /// + /// The value emitted from the fourth source after the subscription has been disposed. private const int Source4ValueAfterDispose = 40; - /// - /// The value emitted from the fifth source after the subscription has been disposed. - /// + /// The value emitted from the fifth source after the subscription has been disposed. private const int Source5ValueAfterDispose = 50; - /// - /// The value emitted from the sixth source after the subscription has been disposed. - /// + /// The value emitted from the sixth source after the subscription has been disposed. private const int Source6ValueAfterDispose = 60; - /// - /// The value emitted from the seventh source after the subscription has been disposed. - /// + /// The value emitted from the seventh source after the subscription has been disposed. private const int Source7ValueAfterDispose = 70; - /// - /// The value emitted from the eighth source after the subscription has been disposed. - /// + /// The value emitted from the eighth source after the subscription has been disposed. private const int Source8ValueAfterDispose = 80; - /// - /// The value emitted from the ninth source after the subscription has been disposed. - /// + /// The value emitted from the ninth source after the subscription has been disposed. private const int Source9ValueAfterDispose = 90; - /// - /// The value emitted from the tenth source after the subscription has been disposed. - /// + /// The value emitted from the tenth source after the subscription has been disposed. private const int Source10ValueAfterDispose = 100; - /// - /// The value emitted from the eleventh source after the subscription has been disposed. - /// + /// The value emitted from the eleventh source after the subscription has been disposed. private const int Source11ValueAfterDispose = 110; - /// - /// Verifies that a null first source throws . - /// + /// Verifies that a null first source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource1_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( (IObservable)null!, new Subject(), new Subject(), @@ -145,23 +93,17 @@ public async Task Constructor_NullSource1_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); + static (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null second source throws . - /// + /// Verifies that a null second source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource2_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), (IObservable)null!, new Subject(), @@ -173,23 +115,17 @@ public async Task Constructor_NullSource2_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); + static (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null third source throws . - /// + /// Verifies that a null third source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource3_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), (IObservable)null!, @@ -201,23 +137,17 @@ public async Task Constructor_NullSource3_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); + static (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fourth source throws . - /// + /// Verifies that a null fourth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource4_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -229,23 +159,17 @@ public async Task Constructor_NullSource4_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); + static (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fifth source throws . - /// + /// Verifies that a null fifth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource5_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -257,23 +181,17 @@ public async Task Constructor_NullSource5_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); + static (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null sixth source throws . - /// + /// Verifies that a null sixth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource6_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -285,23 +203,17 @@ public async Task Constructor_NullSource6_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); + static (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null seventh source throws . - /// + /// Verifies that a null seventh source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource7_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -313,23 +225,17 @@ public async Task Constructor_NullSource7_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); + static (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null eighth source throws . - /// + /// Verifies that a null eighth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource8_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -341,23 +247,17 @@ public async Task Constructor_NullSource8_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); + static (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null ninth source throws . - /// + /// Verifies that a null ninth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource9_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -369,23 +269,17 @@ public async Task Constructor_NullSource9_Throws() (IObservable)null!, new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); + static (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null tenth source throws . - /// + /// Verifies that a null tenth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource10_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -397,23 +291,17 @@ public async Task Constructor_NullSource10_Throws() new Subject(), (IObservable)null!, new Subject(), - (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); + static (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null eleventh source throws . - /// + /// Verifies that a null eleventh source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource11_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -425,19 +313,17 @@ public async Task Constructor_NullSource11_Throws() new Subject(), new Subject(), (IObservable)null!, - (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); + static (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null result selector throws . - /// + /// Verifies that a null result selector throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullResultSelector_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -454,14 +340,8 @@ public async Task Constructor_NullResultSelector_Throws() await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that subscribing with a null observer throws . - /// + /// Verifies that subscribing with a null observer throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Subscribe_NullObserver_Throws() { @@ -477,22 +357,19 @@ public async Task Subscribe_NullObserver_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); + static (a, b, c, d, e, f, g, h, i, j, k) => a + b + c + d + e + f + g + h + i + j + k); var act = () => combined.Subscribe(null!); await Assert.That(act).ThrowsExactly(); } - /// - /// A simple observer implementation that delegates to provided action callbacks. - /// + /// A simple observer implementation that delegates to provided action callbacks. /// The type of elements observed. /// The action to invoke for each observed element. /// The action to invoke when an error occurs. /// The action to invoke when the sequence completes. - private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) - : IObserver + private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) : IObserver { /// public void OnCompleted() => onCompleted(); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest12ObservableTests.Disposal.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest12ObservableTests.Disposal.cs index 8a45bb5..0b0d6e1 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest12ObservableTests.Disposal.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest12ObservableTests.Disposal.cs @@ -8,20 +8,11 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Disposal and error-propagation tests for -/// . -/// +/// Disposal and error-propagation tests for . public partial class CombineLatest12ObservableTests { - /// - /// Verifies that disposing twice does not throw an exception. - /// + /// Verifies that disposing twice does not throw an exception. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Dispose_CalledTwice_NoException() { @@ -38,23 +29,17 @@ public async Task Dispose_CalledTwice_NoException() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); + static (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); - var subscription = combined.Subscribe(new AnonymousObserver(_ => { }, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(static _ => { }, static _ => { }, static () => { })); subscription.Dispose(); subscription.Dispose(); await Assert.That(subscription.GetType()).IsNotNull(); } - /// - /// Verifies that an error after dispose is ignored. - /// + /// Verifies that an error after dispose is ignored. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorAfterDispose_IsIgnored() { @@ -83,13 +68,13 @@ public async Task ErrorAfterDispose_IsIgnored() source10, source11, source12, - (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); + static (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); subscription.Dispose(); source1.OnError(new InvalidOperationException(IgnoredErrorMessage)); @@ -113,10 +98,7 @@ public async Task ErrorAfterDispose_IsIgnored() /// when the subscription has been disposed but the observers are still reachable. /// /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] + [SuppressMessage("Design", "SST1523:Methods should not be too long", Justification = "Length is intrinsic to the fixed CombineLatest arity; each source needs its own line.")] [Test] public async Task ErrorAfterDispose_AllObservers_CoverNullPath() { @@ -145,13 +127,13 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() manual10, manual11, manual12, - (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); + static (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); // Set all has-value flags so TryEmit reaches _observer?.OnNext manual1.Observer!.OnNext(1); @@ -198,14 +180,8 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() await Assert.That(receivedError).IsNull(); } - /// - /// Verifies that an error in the first source observable is propagated to the subscriber. - /// + /// Verifies that an error in the first source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource1_PropagatedToSubscriber() { @@ -234,15 +210,15 @@ public async Task ErrorInSource1_PropagatedToSubscriber() source10, source11, source12, - (a, b, c, d, e, f, g, h, i, j, k, l) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}"); + static (a, b, c, d, e, f, g, h, i, j, k, l) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source1 error"); source1.OnError(expectedError); @@ -252,14 +228,8 @@ public async Task ErrorInSource1_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the second source observable is propagated to the subscriber. - /// + /// Verifies that an error in the second source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource2_PropagatedToSubscriber() { @@ -288,15 +258,15 @@ public async Task ErrorInSource2_PropagatedToSubscriber() source10, source11, source12, - (a, b, c, d, e, f, g, h, i, j, k, l) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}"); + static (a, b, c, d, e, f, g, h, i, j, k, l) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source2 error"); source2.OnError(expectedError); @@ -306,14 +276,8 @@ public async Task ErrorInSource2_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the third source observable is propagated to the subscriber. - /// + /// Verifies that an error in the third source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource3_PropagatedToSubscriber() { @@ -342,15 +306,15 @@ public async Task ErrorInSource3_PropagatedToSubscriber() source10, source11, source12, - (a, b, c, d, e, f, g, h, i, j, k, l) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}"); + static (a, b, c, d, e, f, g, h, i, j, k, l) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source3 error"); source3.OnError(expectedError); @@ -360,14 +324,8 @@ public async Task ErrorInSource3_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fourth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fourth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource4_PropagatedToSubscriber() { @@ -396,15 +354,15 @@ public async Task ErrorInSource4_PropagatedToSubscriber() source10, source11, source12, - (a, b, c, d, e, f, g, h, i, j, k, l) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}"); + static (a, b, c, d, e, f, g, h, i, j, k, l) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source4 error"); source4.OnError(expectedError); @@ -414,14 +372,8 @@ public async Task ErrorInSource4_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fifth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fifth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource5_PropagatedToSubscriber() { @@ -450,15 +402,15 @@ public async Task ErrorInSource5_PropagatedToSubscriber() source10, source11, source12, - (a, b, c, d, e, f, g, h, i, j, k, l) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}"); + static (a, b, c, d, e, f, g, h, i, j, k, l) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source5 error"); source5.OnError(expectedError); @@ -468,14 +420,8 @@ public async Task ErrorInSource5_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the sixth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the sixth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource6_PropagatedToSubscriber() { @@ -504,15 +450,15 @@ public async Task ErrorInSource6_PropagatedToSubscriber() source10, source11, source12, - (a, b, c, d, e, f, g, h, i, j, k, l) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}"); + static (a, b, c, d, e, f, g, h, i, j, k, l) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source6 error"); source6.OnError(expectedError); @@ -522,14 +468,8 @@ public async Task ErrorInSource6_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the seventh source observable is propagated to the subscriber. - /// + /// Verifies that an error in the seventh source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource7_PropagatedToSubscriber() { @@ -558,15 +498,15 @@ public async Task ErrorInSource7_PropagatedToSubscriber() source10, source11, source12, - (a, b, c, d, e, f, g, h, i, j, k, l) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}"); + static (a, b, c, d, e, f, g, h, i, j, k, l) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source7 error"); source7.OnError(expectedError); @@ -576,14 +516,8 @@ public async Task ErrorInSource7_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the eighth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the eighth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource8_PropagatedToSubscriber() { @@ -612,15 +546,15 @@ public async Task ErrorInSource8_PropagatedToSubscriber() source10, source11, source12, - (a, b, c, d, e, f, g, h, i, j, k, l) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}"); + static (a, b, c, d, e, f, g, h, i, j, k, l) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source8 error"); source8.OnError(expectedError); @@ -630,14 +564,8 @@ public async Task ErrorInSource8_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the ninth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the ninth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource9_PropagatedToSubscriber() { @@ -666,15 +594,15 @@ public async Task ErrorInSource9_PropagatedToSubscriber() source10, source11, source12, - (a, b, c, d, e, f, g, h, i, j, k, l) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}"); + static (a, b, c, d, e, f, g, h, i, j, k, l) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source9 error"); source9.OnError(expectedError); @@ -684,14 +612,8 @@ public async Task ErrorInSource9_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the tenth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the tenth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource10_PropagatedToSubscriber() { @@ -720,15 +642,15 @@ public async Task ErrorInSource10_PropagatedToSubscriber() source10, source11, source12, - (a, b, c, d, e, f, g, h, i, j, k, l) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}"); + static (a, b, c, d, e, f, g, h, i, j, k, l) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source10 error"); source10.OnError(expectedError); @@ -738,14 +660,8 @@ public async Task ErrorInSource10_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the eleventh source observable is propagated to the subscriber. - /// + /// Verifies that an error in the eleventh source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource11_PropagatedToSubscriber() { @@ -774,15 +690,15 @@ public async Task ErrorInSource11_PropagatedToSubscriber() source10, source11, source12, - (a, b, c, d, e, f, g, h, i, j, k, l) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}"); + static (a, b, c, d, e, f, g, h, i, j, k, l) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source11 error"); source11.OnError(expectedError); @@ -792,14 +708,8 @@ public async Task ErrorInSource11_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the twelfth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the twelfth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource12_PropagatedToSubscriber() { @@ -828,15 +738,15 @@ public async Task ErrorInSource12_PropagatedToSubscriber() source10, source11, source12, - (a, b, c, d, e, f, g, h, i, j, k, l) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}"); + static (a, b, c, d, e, f, g, h, i, j, k, l) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source12 error"); source12.OnError(expectedError); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest12ObservableTests.Emission.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest12ObservableTests.Emission.cs index 7814327..4e68dbc 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest12ObservableTests.Emission.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest12ObservableTests.Emission.cs @@ -7,20 +7,11 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Emission and combination behaviour tests for -/// . -/// +/// Emission and combination behaviour tests for . public partial class CombineLatest12ObservableTests { - /// - /// Verifies that a source emitting after dispose does not throw. - /// + /// Verifies that a source emitting after dispose does not throw. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task SourceEmitsAfterDispose_NoException() { @@ -49,10 +40,10 @@ public async Task SourceEmitsAfterDispose_NoException() source10, source11, source12, - (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); + static (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); var results = new List(); - var subscription = combined.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); source1.OnNext(1); source2.OnNext(1); @@ -73,14 +64,9 @@ public async Task SourceEmitsAfterDispose_NoException() await Assert.That(results).Count().IsEqualTo(1); } - /// - /// Verifies that OnCompleted from a single source does not propagate completion. - /// + /// Verifies that OnCompleted from a single source does not propagate completion. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] + [SuppressMessage("Design", "SST1523:Methods should not be too long", Justification = "Length is intrinsic to the fixed CombineLatest arity; each source needs its own line.")] [Test] public async Task CompletedInSource_DoesNotPropagateCompletion() { @@ -109,14 +95,14 @@ public async Task CompletedInSource_DoesNotPropagateCompletion() source10, source11, source12, - (a, b, c, d, e, f, g, h, i, j, k, l) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}"); + static (a, b, c, d, e, f, g, h, i, j, k, l) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}"); var completed = false; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, - _ => { }, + static _ => { }, () => completed = true)); source1.OnNext(1); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest12ObservableTests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest12ObservableTests.cs index 55787f3..d53818a 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest12ObservableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest12ObservableTests.cs @@ -7,143 +7,87 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Unit tests for edge cases. -/// +/// Unit tests for edge cases. public partial class CombineLatest12ObservableTests { - /// - /// The exception message used for errors that the subscription is expected to ignore. - /// + /// The exception message used for errors that the subscription is expected to ignore. private const string IgnoredErrorMessage = "should be ignored"; - /// - /// The distinct sample value emitted from the second source during a combination sequence. - /// + /// The distinct sample value emitted from the second source during a combination sequence. private const int Source2Value = 2; - /// - /// The distinct sample value emitted from the third source during a combination sequence. - /// + /// The distinct sample value emitted from the third source during a combination sequence. private const int Source3Value = 3; - /// - /// The distinct sample value emitted from the fourth source during a combination sequence. - /// + /// The distinct sample value emitted from the fourth source during a combination sequence. private const int Source4Value = 4; - /// - /// The distinct sample value emitted from the fifth source during a combination sequence. - /// + /// The distinct sample value emitted from the fifth source during a combination sequence. private const int Source5Value = 5; - /// - /// The distinct sample value emitted from the sixth source during a combination sequence. - /// + /// The distinct sample value emitted from the sixth source during a combination sequence. private const int Source6Value = 6; - /// - /// The distinct sample value emitted from the seventh source during a combination sequence. - /// + /// The distinct sample value emitted from the seventh source during a combination sequence. private const int Source7Value = 7; - /// - /// The distinct sample value emitted from the eighth source during a combination sequence. - /// + /// The distinct sample value emitted from the eighth source during a combination sequence. private const int Source8Value = 8; - /// - /// The distinct sample value emitted from the ninth source during a combination sequence. - /// + /// The distinct sample value emitted from the ninth source during a combination sequence. private const int Source9Value = 9; - /// - /// The distinct sample value emitted from the tenth source during a combination sequence. - /// + /// The distinct sample value emitted from the tenth source during a combination sequence. private const int Source10Value = 10; - /// - /// The distinct sample value emitted from the eleventh source during a combination sequence. - /// + /// The distinct sample value emitted from the eleventh source during a combination sequence. private const int Source11Value = 11; - /// - /// The distinct sample value emitted from the twelfth source during a combination sequence. - /// + /// The distinct sample value emitted from the twelfth source during a combination sequence. private const int Source12Value = 12; - /// - /// The value emitted from the first source after the subscription has been disposed. - /// + /// The value emitted from the first source after the subscription has been disposed. private const int Source1ValueAfterDispose = 10; - /// - /// The value emitted from the second source after the subscription has been disposed. - /// + /// The value emitted from the second source after the subscription has been disposed. private const int Source2ValueAfterDispose = 20; - /// - /// The value emitted from the third source after the subscription has been disposed. - /// + /// The value emitted from the third source after the subscription has been disposed. private const int Source3ValueAfterDispose = 30; - /// - /// The value emitted from the fourth source after the subscription has been disposed. - /// + /// The value emitted from the fourth source after the subscription has been disposed. private const int Source4ValueAfterDispose = 40; - /// - /// The value emitted from the fifth source after the subscription has been disposed. - /// + /// The value emitted from the fifth source after the subscription has been disposed. private const int Source5ValueAfterDispose = 50; - /// - /// The value emitted from the sixth source after the subscription has been disposed. - /// + /// The value emitted from the sixth source after the subscription has been disposed. private const int Source6ValueAfterDispose = 60; - /// - /// The value emitted from the seventh source after the subscription has been disposed. - /// + /// The value emitted from the seventh source after the subscription has been disposed. private const int Source7ValueAfterDispose = 70; - /// - /// The value emitted from the eighth source after the subscription has been disposed. - /// + /// The value emitted from the eighth source after the subscription has been disposed. private const int Source8ValueAfterDispose = 80; - /// - /// The value emitted from the ninth source after the subscription has been disposed. - /// + /// The value emitted from the ninth source after the subscription has been disposed. private const int Source9ValueAfterDispose = 90; - /// - /// The value emitted from the tenth source after the subscription has been disposed. - /// + /// The value emitted from the tenth source after the subscription has been disposed. private const int Source10ValueAfterDispose = 100; - /// - /// The value emitted from the eleventh source after the subscription has been disposed. - /// + /// The value emitted from the eleventh source after the subscription has been disposed. private const int Source11ValueAfterDispose = 110; - /// - /// The value emitted from the twelfth source after the subscription has been disposed. - /// + /// The value emitted from the twelfth source after the subscription has been disposed. private const int Source12ValueAfterDispose = 120; - /// - /// Verifies that a null first source throws . - /// + /// Verifies that a null first source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource1_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( (IObservable)null!, new Subject(), new Subject(), @@ -156,23 +100,17 @@ public async Task Constructor_NullSource1_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); + static (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null second source throws . - /// + /// Verifies that a null second source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource2_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), (IObservable)null!, new Subject(), @@ -185,23 +123,17 @@ public async Task Constructor_NullSource2_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); + static (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null third source throws . - /// + /// Verifies that a null third source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource3_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), (IObservable)null!, @@ -214,23 +146,17 @@ public async Task Constructor_NullSource3_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); + static (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fourth source throws . - /// + /// Verifies that a null fourth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource4_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -243,23 +169,17 @@ public async Task Constructor_NullSource4_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); + static (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fifth source throws . - /// + /// Verifies that a null fifth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource5_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -272,23 +192,17 @@ public async Task Constructor_NullSource5_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); + static (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null sixth source throws . - /// + /// Verifies that a null sixth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource6_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -301,23 +215,17 @@ public async Task Constructor_NullSource6_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); + static (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null seventh source throws . - /// + /// Verifies that a null seventh source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource7_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -330,23 +238,17 @@ public async Task Constructor_NullSource7_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); + static (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null eighth source throws . - /// + /// Verifies that a null eighth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource8_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -359,23 +261,17 @@ public async Task Constructor_NullSource8_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); + static (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null ninth source throws . - /// + /// Verifies that a null ninth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource9_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -388,23 +284,17 @@ public async Task Constructor_NullSource9_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); + static (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null tenth source throws . - /// + /// Verifies that a null tenth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource10_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -417,23 +307,17 @@ public async Task Constructor_NullSource10_Throws() (IObservable)null!, new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); + static (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null eleventh source throws . - /// + /// Verifies that a null eleventh source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource11_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -446,23 +330,17 @@ public async Task Constructor_NullSource11_Throws() new Subject(), (IObservable)null!, new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); + static (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null twelfth source throws . - /// + /// Verifies that a null twelfth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource12_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -475,19 +353,17 @@ public async Task Constructor_NullSource12_Throws() new Subject(), new Subject(), (IObservable)null!, - (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); + static (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null result selector throws . - /// + /// Verifies that a null result selector throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullResultSelector_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -505,14 +381,8 @@ public async Task Constructor_NullResultSelector_Throws() await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that subscribing with a null observer throws . - /// + /// Verifies that subscribing with a null observer throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Subscribe_NullObserver_Throws() { @@ -529,22 +399,19 @@ public async Task Subscribe_NullObserver_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); + static (a, b, c, d, e, f, g, h, i, j, k, l) => a + b + c + d + e + f + g + h + i + j + k + l); var act = () => combined.Subscribe(null!); await Assert.That(act).ThrowsExactly(); } - /// - /// A simple observer implementation that delegates to provided action callbacks. - /// + /// A simple observer implementation that delegates to provided action callbacks. /// The type of elements observed. /// The action to invoke for each observed element. /// The action to invoke when an error occurs. /// The action to invoke when the sequence completes. - private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) - : IObserver + private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) : IObserver { /// public void OnCompleted() => onCompleted(); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest13ObservableTests.Completion.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest13ObservableTests.Completion.cs index daf9c61..b82b195 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest13ObservableTests.Completion.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest13ObservableTests.Completion.cs @@ -8,19 +8,12 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Completion-propagation tests for . -/// +/// Completion-propagation tests for . public partial class CombineLatest13ObservableTests { - /// - /// Verifies that OnCompleted from a single source does not propagate completion. - /// + /// Verifies that OnCompleted from a single source does not propagate completion. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] + [SuppressMessage("Design", "SST1523:Methods should not be too long", Justification = "Length is intrinsic to the fixed CombineLatest arity; each source needs its own line.")] [Test] public async Task CompletedInSource_DoesNotPropagateCompletion() { @@ -51,14 +44,14 @@ public async Task CompletedInSource_DoesNotPropagateCompletion() source11, source12, source13, - (a, b, c, d, e, f, g, h, i, j, k, l, m) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}"); var completed = false; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, - _ => { }, + static _ => { }, () => completed = true)); source1.OnNext(1); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest13ObservableTests.Disposal.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest13ObservableTests.Disposal.cs index 7c0f50d..3b2adac 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest13ObservableTests.Disposal.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest13ObservableTests.Disposal.cs @@ -9,19 +9,11 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Disposal and post-dispose behavior tests for . -/// +/// Disposal and post-dispose behavior tests for . public partial class CombineLatest13ObservableTests { - /// - /// Verifies that disposing twice does not throw an exception. - /// + /// Verifies that disposing twice does not throw an exception. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Dispose_CalledTwice_NoException() { @@ -39,23 +31,17 @@ public async Task Dispose_CalledTwice_NoException() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); - var subscription = combined.Subscribe(new AnonymousObserver(_ => { }, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(static _ => { }, static _ => { }, static () => { })); subscription.Dispose(); subscription.Dispose(); await Assert.That(subscription.GetType()).IsNotNull(); } - /// - /// Verifies that a source emitting after dispose does not throw. - /// + /// Verifies that a source emitting after dispose does not throw. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task SourceEmitsAfterDispose_NoException() { @@ -86,10 +72,10 @@ public async Task SourceEmitsAfterDispose_NoException() source11, source12, source13, - (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); var results = new List(); - var subscription = combined.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); source1.OnNext(1); source2.OnNext(1); @@ -111,14 +97,8 @@ public async Task SourceEmitsAfterDispose_NoException() await Assert.That(results).Count().IsEqualTo(1); } - /// - /// Verifies that an error after dispose is ignored. - /// + /// Verifies that an error after dispose is ignored. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorAfterDispose_IsIgnored() { @@ -149,13 +129,13 @@ public async Task ErrorAfterDispose_IsIgnored() source11, source12, source13, - (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); subscription.Dispose(); source1.OnError(new InvalidOperationException(IgnoredErrorMessage)); @@ -180,10 +160,7 @@ public async Task ErrorAfterDispose_IsIgnored() /// when the subscription has been disposed but the observers are still reachable. /// /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] + [SuppressMessage("Design", "SST1523:Methods should not be too long", Justification = "Length is intrinsic to the fixed CombineLatest arity; each source needs its own line.")] [Test] public async Task ErrorAfterDispose_AllObservers_CoverNullPath() { @@ -214,13 +191,13 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() manual11, manual12, manual13, - (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); // Set all has-value flags so TryEmit reaches _observer?.OnNext manual1.Observer!.OnNext(1); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest13ObservableTests.Emission.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest13ObservableTests.Emission.cs index c4b6f23..eae35c7 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest13ObservableTests.Emission.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest13ObservableTests.Emission.cs @@ -8,19 +8,11 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Per-source error-propagation tests (part 1) for . -/// +/// Per-source error-propagation tests (part 1) for . public partial class CombineLatest13ObservableTests { - /// - /// Verifies that an error in the first source observable is propagated to the subscriber. - /// + /// Verifies that an error in the first source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource1_PropagatedToSubscriber() { @@ -51,15 +43,15 @@ public async Task ErrorInSource1_PropagatedToSubscriber() source11, source12, source13, - (a, b, c, d, e, f, g, h, i, j, k, l, m) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source1 error"); source1.OnError(expectedError); @@ -69,14 +61,8 @@ public async Task ErrorInSource1_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the second source observable is propagated to the subscriber. - /// + /// Verifies that an error in the second source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource2_PropagatedToSubscriber() { @@ -107,15 +93,15 @@ public async Task ErrorInSource2_PropagatedToSubscriber() source11, source12, source13, - (a, b, c, d, e, f, g, h, i, j, k, l, m) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source2 error"); source2.OnError(expectedError); @@ -125,14 +111,8 @@ public async Task ErrorInSource2_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the third source observable is propagated to the subscriber. - /// + /// Verifies that an error in the third source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource3_PropagatedToSubscriber() { @@ -163,15 +143,15 @@ public async Task ErrorInSource3_PropagatedToSubscriber() source11, source12, source13, - (a, b, c, d, e, f, g, h, i, j, k, l, m) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source3 error"); source3.OnError(expectedError); @@ -181,14 +161,8 @@ public async Task ErrorInSource3_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fourth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fourth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource4_PropagatedToSubscriber() { @@ -219,15 +193,15 @@ public async Task ErrorInSource4_PropagatedToSubscriber() source11, source12, source13, - (a, b, c, d, e, f, g, h, i, j, k, l, m) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source4 error"); source4.OnError(expectedError); @@ -237,14 +211,8 @@ public async Task ErrorInSource4_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fifth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fifth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource5_PropagatedToSubscriber() { @@ -275,15 +243,15 @@ public async Task ErrorInSource5_PropagatedToSubscriber() source11, source12, source13, - (a, b, c, d, e, f, g, h, i, j, k, l, m) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source5 error"); source5.OnError(expectedError); @@ -293,14 +261,8 @@ public async Task ErrorInSource5_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the sixth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the sixth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource6_PropagatedToSubscriber() { @@ -331,15 +293,15 @@ public async Task ErrorInSource6_PropagatedToSubscriber() source11, source12, source13, - (a, b, c, d, e, f, g, h, i, j, k, l, m) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source6 error"); source6.OnError(expectedError); @@ -349,14 +311,8 @@ public async Task ErrorInSource6_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the seventh source observable is propagated to the subscriber. - /// + /// Verifies that an error in the seventh source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource7_PropagatedToSubscriber() { @@ -387,15 +343,15 @@ public async Task ErrorInSource7_PropagatedToSubscriber() source11, source12, source13, - (a, b, c, d, e, f, g, h, i, j, k, l, m) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source7 error"); source7.OnError(expectedError); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest13ObservableTests.Emission2.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest13ObservableTests.Emission2.cs index 3cab8cb..dd4a7d6 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest13ObservableTests.Emission2.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest13ObservableTests.Emission2.cs @@ -8,19 +8,11 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Per-source error-propagation tests (part 2) for . -/// +/// Per-source error-propagation tests (part 2) for . public partial class CombineLatest13ObservableTests { - /// - /// Verifies that an error in the eighth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the eighth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource8_PropagatedToSubscriber() { @@ -51,15 +43,15 @@ public async Task ErrorInSource8_PropagatedToSubscriber() source11, source12, source13, - (a, b, c, d, e, f, g, h, i, j, k, l, m) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source8 error"); source8.OnError(expectedError); @@ -69,14 +61,8 @@ public async Task ErrorInSource8_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the ninth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the ninth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource9_PropagatedToSubscriber() { @@ -107,15 +93,15 @@ public async Task ErrorInSource9_PropagatedToSubscriber() source11, source12, source13, - (a, b, c, d, e, f, g, h, i, j, k, l, m) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source9 error"); source9.OnError(expectedError); @@ -125,14 +111,8 @@ public async Task ErrorInSource9_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the tenth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the tenth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource10_PropagatedToSubscriber() { @@ -163,15 +143,15 @@ public async Task ErrorInSource10_PropagatedToSubscriber() source11, source12, source13, - (a, b, c, d, e, f, g, h, i, j, k, l, m) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source10 error"); source10.OnError(expectedError); @@ -181,14 +161,8 @@ public async Task ErrorInSource10_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the eleventh source observable is propagated to the subscriber. - /// + /// Verifies that an error in the eleventh source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource11_PropagatedToSubscriber() { @@ -219,15 +193,15 @@ public async Task ErrorInSource11_PropagatedToSubscriber() source11, source12, source13, - (a, b, c, d, e, f, g, h, i, j, k, l, m) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source11 error"); source11.OnError(expectedError); @@ -237,14 +211,8 @@ public async Task ErrorInSource11_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the twelfth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the twelfth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource12_PropagatedToSubscriber() { @@ -275,15 +243,15 @@ public async Task ErrorInSource12_PropagatedToSubscriber() source11, source12, source13, - (a, b, c, d, e, f, g, h, i, j, k, l, m) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source12 error"); source12.OnError(expectedError); @@ -293,14 +261,8 @@ public async Task ErrorInSource12_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the thirteenth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the thirteenth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource13_PropagatedToSubscriber() { @@ -331,15 +293,15 @@ public async Task ErrorInSource13_PropagatedToSubscriber() source11, source12, source13, - (a, b, c, d, e, f, g, h, i, j, k, l, m) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source13 error"); source13.OnError(expectedError); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest13ObservableTests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest13ObservableTests.cs index 2b6145f..51ad020 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest13ObservableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest13ObservableTests.cs @@ -8,153 +8,93 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Unit tests for edge cases. -/// +/// Unit tests for edge cases. public partial class CombineLatest13ObservableTests { - /// - /// Sample value emitted by the second source under test. - /// + /// Sample value emitted by the second source under test. private const int SampleValue2 = 2; - /// - /// Sample value emitted by the third source under test. - /// + /// Sample value emitted by the third source under test. private const int SampleValue3 = 3; - /// - /// Sample value emitted by the fourth source under test. - /// + /// Sample value emitted by the fourth source under test. private const int SampleValue4 = 4; - /// - /// Sample value emitted by the fifth source under test. - /// + /// Sample value emitted by the fifth source under test. private const int SampleValue5 = 5; - /// - /// Sample value emitted by the sixth source under test. - /// + /// Sample value emitted by the sixth source under test. private const int SampleValue6 = 6; - /// - /// Sample value emitted by the seventh source under test. - /// + /// Sample value emitted by the seventh source under test. private const int SampleValue7 = 7; - /// - /// Sample value emitted by the eighth source under test. - /// + /// Sample value emitted by the eighth source under test. private const int SampleValue8 = 8; - /// - /// Sample value emitted by the ninth source under test. - /// + /// Sample value emitted by the ninth source under test. private const int SampleValue9 = 9; - /// - /// Sample value emitted by the tenth source under test. - /// + /// Sample value emitted by the tenth source under test. private const int SampleValue10 = 10; - /// - /// Sample value emitted by the eleventh source under test. - /// + /// Sample value emitted by the eleventh source under test. private const int SampleValue11 = 11; - /// - /// Sample value emitted by the twelfth source under test. - /// + /// Sample value emitted by the twelfth source under test. private const int SampleValue12 = 12; - /// - /// Sample value emitted by the thirteenth source under test. - /// + /// Sample value emitted by the thirteenth source under test. private const int SampleValue13 = 13; - /// - /// Sample value emitted by the first source after the subscription is disposed. - /// + /// Sample value emitted by the first source after the subscription is disposed. private const int PostDisposeValue1 = 10; - /// - /// Sample value emitted by the second source after the subscription is disposed. - /// + /// Sample value emitted by the second source after the subscription is disposed. private const int PostDisposeValue2 = 20; - /// - /// Sample value emitted by the third source after the subscription is disposed. - /// + /// Sample value emitted by the third source after the subscription is disposed. private const int PostDisposeValue3 = 30; - /// - /// Sample value emitted by the fourth source after the subscription is disposed. - /// + /// Sample value emitted by the fourth source after the subscription is disposed. private const int PostDisposeValue4 = 40; - /// - /// Sample value emitted by the fifth source after the subscription is disposed. - /// + /// Sample value emitted by the fifth source after the subscription is disposed. private const int PostDisposeValue5 = 50; - /// - /// Sample value emitted by the sixth source after the subscription is disposed. - /// + /// Sample value emitted by the sixth source after the subscription is disposed. private const int PostDisposeValue6 = 60; - /// - /// Sample value emitted by the seventh source after the subscription is disposed. - /// + /// Sample value emitted by the seventh source after the subscription is disposed. private const int PostDisposeValue7 = 70; - /// - /// Sample value emitted by the eighth source after the subscription is disposed. - /// + /// Sample value emitted by the eighth source after the subscription is disposed. private const int PostDisposeValue8 = 80; - /// - /// Sample value emitted by the ninth source after the subscription is disposed. - /// + /// Sample value emitted by the ninth source after the subscription is disposed. private const int PostDisposeValue9 = 90; - /// - /// Sample value emitted by the tenth source after the subscription is disposed. - /// + /// Sample value emitted by the tenth source after the subscription is disposed. private const int PostDisposeValue10 = 100; - /// - /// Sample value emitted by the eleventh source after the subscription is disposed. - /// + /// Sample value emitted by the eleventh source after the subscription is disposed. private const int PostDisposeValue11 = 110; - /// - /// Sample value emitted by the twelfth source after the subscription is disposed. - /// + /// Sample value emitted by the twelfth source after the subscription is disposed. private const int PostDisposeValue12 = 120; - /// - /// Sample value emitted by the thirteenth source after the subscription is disposed. - /// + /// Sample value emitted by the thirteenth source after the subscription is disposed. private const int PostDisposeValue13 = 130; - /// - /// The message used for errors that are expected to be ignored after disposal. - /// + /// The message used for errors that are expected to be ignored after disposal. private const string IgnoredErrorMessage = "should be ignored"; - /// - /// Verifies that a null first source throws . - /// + /// Verifies that a null first source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource1_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( (IObservable)null!, new Subject(), new Subject(), @@ -168,23 +108,17 @@ public async Task Constructor_NullSource1_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null second source throws . - /// + /// Verifies that a null second source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource2_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), (IObservable)null!, new Subject(), @@ -198,23 +132,17 @@ public async Task Constructor_NullSource2_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null third source throws . - /// + /// Verifies that a null third source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource3_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), (IObservable)null!, @@ -228,23 +156,17 @@ public async Task Constructor_NullSource3_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fourth source throws . - /// + /// Verifies that a null fourth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource4_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -258,23 +180,17 @@ public async Task Constructor_NullSource4_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fifth source throws . - /// + /// Verifies that a null fifth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource5_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -288,23 +204,17 @@ public async Task Constructor_NullSource5_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null sixth source throws . - /// + /// Verifies that a null sixth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource6_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -318,23 +228,17 @@ public async Task Constructor_NullSource6_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null seventh source throws . - /// + /// Verifies that a null seventh source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource7_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -348,23 +252,17 @@ public async Task Constructor_NullSource7_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null eighth source throws . - /// + /// Verifies that a null eighth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource8_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -378,23 +276,17 @@ public async Task Constructor_NullSource8_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null ninth source throws . - /// + /// Verifies that a null ninth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource9_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -408,23 +300,17 @@ public async Task Constructor_NullSource9_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null tenth source throws . - /// + /// Verifies that a null tenth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource10_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -438,23 +324,17 @@ public async Task Constructor_NullSource10_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null eleventh source throws . - /// + /// Verifies that a null eleventh source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource11_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -468,23 +348,17 @@ public async Task Constructor_NullSource11_Throws() (IObservable)null!, new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null twelfth source throws . - /// + /// Verifies that a null twelfth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource12_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -498,23 +372,17 @@ public async Task Constructor_NullSource12_Throws() new Subject(), (IObservable)null!, new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null thirteenth source throws . - /// + /// Verifies that a null thirteenth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource13_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -528,23 +396,17 @@ public async Task Constructor_NullSource13_Throws() new Subject(), new Subject(), (IObservable)null!, - (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null result selector throws . - /// + /// Verifies that a null result selector throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullResultSelector_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -563,14 +425,8 @@ public async Task Constructor_NullResultSelector_Throws() await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that subscribing with a null observer throws . - /// + /// Verifies that subscribing with a null observer throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Subscribe_NullObserver_Throws() { @@ -588,22 +444,19 @@ public async Task Subscribe_NullObserver_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); + static (a, b, c, d, e, f, g, h, i, j, k, l, m) => a + b + c + d + e + f + g + h + i + j + k + l + m); var act = () => combined.Subscribe(null!); await Assert.That(act).ThrowsExactly(); } - /// - /// A simple observer implementation that delegates to provided action callbacks. - /// + /// A simple observer implementation that delegates to provided action callbacks. /// The type of elements observed. /// The action to invoke for each observed element. /// The action to invoke when an error occurs. /// The action to invoke when the sequence completes. - private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) - : IObserver + private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) : IObserver { /// public void OnCompleted() => onCompleted(); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest14ObservableTests.Completion.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest14ObservableTests.Completion.cs index 4a14d92..fe64648 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest14ObservableTests.Completion.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest14ObservableTests.Completion.cs @@ -8,19 +8,12 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Completion-propagation tests for . -/// +/// Completion-propagation tests for . public partial class CombineLatest14ObservableTests { - /// - /// Verifies that OnCompleted from a single source does not propagate completion. - /// + /// Verifies that OnCompleted from a single source does not propagate completion. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] + [SuppressMessage("Design", "SST1523:Methods should not be too long", Justification = "Length is intrinsic to the fixed CombineLatest arity; each source needs its own line.")] [Test] public async Task CompletedInSource_DoesNotPropagateCompletion() { @@ -53,14 +46,14 @@ public async Task CompletedInSource_DoesNotPropagateCompletion() source12, source13, source14, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); var completed = false; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, - _ => { }, + static _ => { }, () => completed = true)); source1.OnNext(1); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest14ObservableTests.Disposal.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest14ObservableTests.Disposal.cs index d3c23f9..0fe1349 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest14ObservableTests.Disposal.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest14ObservableTests.Disposal.cs @@ -9,19 +9,11 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Disposal and post-dispose behavior tests for . -/// +/// Disposal and post-dispose behavior tests for . public partial class CombineLatest14ObservableTests { - /// - /// Verifies that disposing twice does not throw an exception. - /// + /// Verifies that disposing twice does not throw an exception. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Dispose_CalledTwice_NoException() { @@ -40,23 +32,17 @@ public async Task Dispose_CalledTwice_NoException() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); - var subscription = combined.Subscribe(new AnonymousObserver(_ => { }, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(static _ => { }, static _ => { }, static () => { })); subscription.Dispose(); subscription.Dispose(); await Assert.That(subscription.GetType()).IsNotNull(); } - /// - /// Verifies that a source emitting after dispose does not throw. - /// + /// Verifies that a source emitting after dispose does not throw. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task SourceEmitsAfterDispose_NoException() { @@ -89,10 +75,10 @@ public async Task SourceEmitsAfterDispose_NoException() source12, source13, source14, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); var results = new List(); - var subscription = combined.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); source1.OnNext(1); source2.OnNext(1); @@ -115,14 +101,8 @@ public async Task SourceEmitsAfterDispose_NoException() await Assert.That(results).Count().IsEqualTo(1); } - /// - /// Verifies that an error after dispose is ignored. - /// + /// Verifies that an error after dispose is ignored. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorAfterDispose_IsIgnored() { @@ -155,13 +135,13 @@ public async Task ErrorAfterDispose_IsIgnored() source12, source13, source14, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); subscription.Dispose(); source1.OnError(new InvalidOperationException(IgnoredErrorMessage)); @@ -187,10 +167,7 @@ public async Task ErrorAfterDispose_IsIgnored() /// when the subscription has been disposed but the observers are still reachable. /// /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] + [SuppressMessage("Design", "SST1523:Methods should not be too long", Justification = "Length is intrinsic to the fixed CombineLatest arity; each source needs its own line.")] [Test] public async Task ErrorAfterDispose_AllObservers_CoverNullPath() { @@ -223,13 +200,13 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() manual12, manual13, manual14, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); // Set all has-value flags so TryEmit reaches _observer?.OnNext manual1.Observer!.OnNext(1); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest14ObservableTests.Emission.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest14ObservableTests.Emission.cs index afb0343..b96fb53 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest14ObservableTests.Emission.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest14ObservableTests.Emission.cs @@ -8,19 +8,11 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Per-source error-propagation tests (part 1) for . -/// +/// Per-source error-propagation tests (part 1) for . public partial class CombineLatest14ObservableTests { - /// - /// Verifies that an error in the first source observable is propagated to the subscriber. - /// + /// Verifies that an error in the first source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource1_PropagatedToSubscriber() { @@ -53,15 +45,15 @@ public async Task ErrorInSource1_PropagatedToSubscriber() source12, source13, source14, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source1 error"); source1.OnError(expectedError); @@ -71,14 +63,8 @@ public async Task ErrorInSource1_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the second source observable is propagated to the subscriber. - /// + /// Verifies that an error in the second source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource2_PropagatedToSubscriber() { @@ -111,15 +97,15 @@ public async Task ErrorInSource2_PropagatedToSubscriber() source12, source13, source14, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source2 error"); source2.OnError(expectedError); @@ -129,14 +115,8 @@ public async Task ErrorInSource2_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the third source observable is propagated to the subscriber. - /// + /// Verifies that an error in the third source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource3_PropagatedToSubscriber() { @@ -169,15 +149,15 @@ public async Task ErrorInSource3_PropagatedToSubscriber() source12, source13, source14, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source3 error"); source3.OnError(expectedError); @@ -187,14 +167,8 @@ public async Task ErrorInSource3_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fourth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fourth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource4_PropagatedToSubscriber() { @@ -227,15 +201,15 @@ public async Task ErrorInSource4_PropagatedToSubscriber() source12, source13, source14, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source4 error"); source4.OnError(expectedError); @@ -245,14 +219,8 @@ public async Task ErrorInSource4_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fifth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fifth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource5_PropagatedToSubscriber() { @@ -285,15 +253,15 @@ public async Task ErrorInSource5_PropagatedToSubscriber() source12, source13, source14, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source5 error"); source5.OnError(expectedError); @@ -303,14 +271,8 @@ public async Task ErrorInSource5_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the sixth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the sixth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource6_PropagatedToSubscriber() { @@ -343,15 +305,15 @@ public async Task ErrorInSource6_PropagatedToSubscriber() source12, source13, source14, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source6 error"); source6.OnError(expectedError); @@ -361,14 +323,8 @@ public async Task ErrorInSource6_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the seventh source observable is propagated to the subscriber. - /// + /// Verifies that an error in the seventh source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource7_PropagatedToSubscriber() { @@ -401,15 +357,15 @@ public async Task ErrorInSource7_PropagatedToSubscriber() source12, source13, source14, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source7 error"); source7.OnError(expectedError); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest14ObservableTests.Emission2.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest14ObservableTests.Emission2.cs index 4906e7a..92a64a2 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest14ObservableTests.Emission2.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest14ObservableTests.Emission2.cs @@ -8,19 +8,11 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Per-source error-propagation tests (part 2) for . -/// +/// Per-source error-propagation tests (part 2) for . public partial class CombineLatest14ObservableTests { - /// - /// Verifies that an error in the eighth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the eighth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource8_PropagatedToSubscriber() { @@ -53,15 +45,15 @@ public async Task ErrorInSource8_PropagatedToSubscriber() source12, source13, source14, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source8 error"); source8.OnError(expectedError); @@ -71,14 +63,8 @@ public async Task ErrorInSource8_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the ninth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the ninth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource9_PropagatedToSubscriber() { @@ -111,15 +97,15 @@ public async Task ErrorInSource9_PropagatedToSubscriber() source12, source13, source14, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source9 error"); source9.OnError(expectedError); @@ -129,14 +115,8 @@ public async Task ErrorInSource9_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the tenth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the tenth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource10_PropagatedToSubscriber() { @@ -169,15 +149,15 @@ public async Task ErrorInSource10_PropagatedToSubscriber() source12, source13, source14, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source10 error"); source10.OnError(expectedError); @@ -187,14 +167,8 @@ public async Task ErrorInSource10_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the eleventh source observable is propagated to the subscriber. - /// + /// Verifies that an error in the eleventh source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource11_PropagatedToSubscriber() { @@ -227,15 +201,15 @@ public async Task ErrorInSource11_PropagatedToSubscriber() source12, source13, source14, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source11 error"); source11.OnError(expectedError); @@ -245,14 +219,8 @@ public async Task ErrorInSource11_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the twelfth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the twelfth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource12_PropagatedToSubscriber() { @@ -285,15 +253,15 @@ public async Task ErrorInSource12_PropagatedToSubscriber() source12, source13, source14, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source12 error"); source12.OnError(expectedError); @@ -303,14 +271,8 @@ public async Task ErrorInSource12_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the thirteenth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the thirteenth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource13_PropagatedToSubscriber() { @@ -343,15 +305,15 @@ public async Task ErrorInSource13_PropagatedToSubscriber() source12, source13, source14, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source13 error"); source13.OnError(expectedError); @@ -361,14 +323,8 @@ public async Task ErrorInSource13_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fourteenth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fourteenth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource14_PropagatedToSubscriber() { @@ -401,15 +357,15 @@ public async Task ErrorInSource14_PropagatedToSubscriber() source12, source13, source14, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source14 error"); source14.OnError(expectedError); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest14ObservableTests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest14ObservableTests.cs index 9575cc2..eb5163b 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest14ObservableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest14ObservableTests.cs @@ -8,163 +8,99 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Unit tests for edge cases. -/// +/// Unit tests for edge cases. public partial class CombineLatest14ObservableTests { - /// - /// Sample value emitted by the second source under test. - /// + /// Sample value emitted by the second source under test. private const int SampleValue2 = 2; - /// - /// Sample value emitted by the third source under test. - /// + /// Sample value emitted by the third source under test. private const int SampleValue3 = 3; - /// - /// Sample value emitted by the fourth source under test. - /// + /// Sample value emitted by the fourth source under test. private const int SampleValue4 = 4; - /// - /// Sample value emitted by the fifth source under test. - /// + /// Sample value emitted by the fifth source under test. private const int SampleValue5 = 5; - /// - /// Sample value emitted by the sixth source under test. - /// + /// Sample value emitted by the sixth source under test. private const int SampleValue6 = 6; - /// - /// Sample value emitted by the seventh source under test. - /// + /// Sample value emitted by the seventh source under test. private const int SampleValue7 = 7; - /// - /// Sample value emitted by the eighth source under test. - /// + /// Sample value emitted by the eighth source under test. private const int SampleValue8 = 8; - /// - /// Sample value emitted by the ninth source under test. - /// + /// Sample value emitted by the ninth source under test. private const int SampleValue9 = 9; - /// - /// Sample value emitted by the tenth source under test. - /// + /// Sample value emitted by the tenth source under test. private const int SampleValue10 = 10; - /// - /// Sample value emitted by the eleventh source under test. - /// + /// Sample value emitted by the eleventh source under test. private const int SampleValue11 = 11; - /// - /// Sample value emitted by the twelfth source under test. - /// + /// Sample value emitted by the twelfth source under test. private const int SampleValue12 = 12; - /// - /// Sample value emitted by the thirteenth source under test. - /// + /// Sample value emitted by the thirteenth source under test. private const int SampleValue13 = 13; - /// - /// Sample value emitted by the fourteenth source under test. - /// + /// Sample value emitted by the fourteenth source under test. private const int SampleValue14 = 14; - /// - /// Sample value emitted by the first source after the subscription is disposed. - /// + /// Sample value emitted by the first source after the subscription is disposed. private const int PostDisposeValue1 = 10; - /// - /// Sample value emitted by the second source after the subscription is disposed. - /// + /// Sample value emitted by the second source after the subscription is disposed. private const int PostDisposeValue2 = 20; - /// - /// Sample value emitted by the third source after the subscription is disposed. - /// + /// Sample value emitted by the third source after the subscription is disposed. private const int PostDisposeValue3 = 30; - /// - /// Sample value emitted by the fourth source after the subscription is disposed. - /// + /// Sample value emitted by the fourth source after the subscription is disposed. private const int PostDisposeValue4 = 40; - /// - /// Sample value emitted by the fifth source after the subscription is disposed. - /// + /// Sample value emitted by the fifth source after the subscription is disposed. private const int PostDisposeValue5 = 50; - /// - /// Sample value emitted by the sixth source after the subscription is disposed. - /// + /// Sample value emitted by the sixth source after the subscription is disposed. private const int PostDisposeValue6 = 60; - /// - /// Sample value emitted by the seventh source after the subscription is disposed. - /// + /// Sample value emitted by the seventh source after the subscription is disposed. private const int PostDisposeValue7 = 70; - /// - /// Sample value emitted by the eighth source after the subscription is disposed. - /// + /// Sample value emitted by the eighth source after the subscription is disposed. private const int PostDisposeValue8 = 80; - /// - /// Sample value emitted by the ninth source after the subscription is disposed. - /// + /// Sample value emitted by the ninth source after the subscription is disposed. private const int PostDisposeValue9 = 90; - /// - /// Sample value emitted by the tenth source after the subscription is disposed. - /// + /// Sample value emitted by the tenth source after the subscription is disposed. private const int PostDisposeValue10 = 100; - /// - /// Sample value emitted by the eleventh source after the subscription is disposed. - /// + /// Sample value emitted by the eleventh source after the subscription is disposed. private const int PostDisposeValue11 = 110; - /// - /// Sample value emitted by the twelfth source after the subscription is disposed. - /// + /// Sample value emitted by the twelfth source after the subscription is disposed. private const int PostDisposeValue12 = 120; - /// - /// Sample value emitted by the thirteenth source after the subscription is disposed. - /// + /// Sample value emitted by the thirteenth source after the subscription is disposed. private const int PostDisposeValue13 = 130; - /// - /// Sample value emitted by the fourteenth source after the subscription is disposed. - /// + /// Sample value emitted by the fourteenth source after the subscription is disposed. private const int PostDisposeValue14 = 140; - /// - /// The message used for errors that are expected to be ignored after disposal. - /// + /// The message used for errors that are expected to be ignored after disposal. private const string IgnoredErrorMessage = "should be ignored"; - /// - /// Verifies that a null first source throws . - /// + /// Verifies that a null first source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource1_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( (IObservable)null!, new Subject(), new Subject(), @@ -179,23 +115,17 @@ public async Task Constructor_NullSource1_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null second source throws . - /// + /// Verifies that a null second source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource2_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), (IObservable)null!, new Subject(), @@ -210,23 +140,17 @@ public async Task Constructor_NullSource2_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null third source throws . - /// + /// Verifies that a null third source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource3_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), (IObservable)null!, @@ -241,23 +165,17 @@ public async Task Constructor_NullSource3_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fourth source throws . - /// + /// Verifies that a null fourth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource4_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -272,23 +190,17 @@ public async Task Constructor_NullSource4_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fifth source throws . - /// + /// Verifies that a null fifth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource5_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -303,23 +215,17 @@ public async Task Constructor_NullSource5_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null sixth source throws . - /// + /// Verifies that a null sixth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource6_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -334,23 +240,17 @@ public async Task Constructor_NullSource6_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null seventh source throws . - /// + /// Verifies that a null seventh source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource7_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -365,23 +265,17 @@ public async Task Constructor_NullSource7_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null eighth source throws . - /// + /// Verifies that a null eighth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource8_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -396,23 +290,17 @@ public async Task Constructor_NullSource8_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null ninth source throws . - /// + /// Verifies that a null ninth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource9_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -427,23 +315,17 @@ public async Task Constructor_NullSource9_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null tenth source throws . - /// + /// Verifies that a null tenth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource10_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -458,23 +340,17 @@ public async Task Constructor_NullSource10_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null eleventh source throws . - /// + /// Verifies that a null eleventh source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource11_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -489,23 +365,17 @@ public async Task Constructor_NullSource11_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null twelfth source throws . - /// + /// Verifies that a null twelfth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource12_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -520,23 +390,17 @@ public async Task Constructor_NullSource12_Throws() (IObservable)null!, new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null thirteenth source throws . - /// + /// Verifies that a null thirteenth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource13_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -551,23 +415,17 @@ public async Task Constructor_NullSource13_Throws() new Subject(), (IObservable)null!, new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fourteenth source throws . - /// + /// Verifies that a null fourteenth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource14_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -582,23 +440,17 @@ public async Task Constructor_NullSource14_Throws() new Subject(), new Subject(), (IObservable)null!, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null result selector throws . - /// + /// Verifies that a null result selector throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullResultSelector_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -618,14 +470,8 @@ public async Task Constructor_NullResultSelector_Throws() await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that subscribing with a null observer throws . - /// + /// Verifies that subscribing with a null observer throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Subscribe_NullObserver_Throws() { @@ -644,22 +490,19 @@ public async Task Subscribe_NullObserver_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a + b + c + d + e + f + g + h + i + j + k + l + m + n); var act = () => combined.Subscribe(null!); await Assert.That(act).ThrowsExactly(); } - /// - /// A simple observer implementation that delegates to provided action callbacks. - /// + /// A simple observer implementation that delegates to provided action callbacks. /// The type of elements observed. /// The action to invoke for each observed element. /// The action to invoke when an error occurs. /// The action to invoke when the sequence completes. - private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) - : IObserver + private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) : IObserver { /// public void OnCompleted() => onCompleted(); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest15ObservableTests.Completion.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest15ObservableTests.Completion.cs index 935cbac..401ba5e 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest15ObservableTests.Completion.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest15ObservableTests.Completion.cs @@ -8,19 +8,12 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Completion-propagation tests for . -/// +/// Completion-propagation tests for . public partial class CombineLatest15ObservableTests { - /// - /// Verifies that OnCompleted from a single source does not propagate completion. - /// + /// Verifies that OnCompleted from a single source does not propagate completion. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] + [SuppressMessage("Design", "SST1523:Methods should not be too long", Justification = "Length is intrinsic to the fixed CombineLatest arity; each source needs its own line.")] [Test] public async Task CompletedInSource_DoesNotPropagateCompletion() { @@ -55,14 +48,14 @@ public async Task CompletedInSource_DoesNotPropagateCompletion() source13, source14, source15, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); var completed = false; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, - _ => { }, + static _ => { }, () => completed = true)); source1.OnNext(1); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest15ObservableTests.Disposal.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest15ObservableTests.Disposal.cs index 1f41c50..029bce5 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest15ObservableTests.Disposal.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest15ObservableTests.Disposal.cs @@ -9,19 +9,11 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Disposal and post-dispose behavior tests for . -/// +/// Disposal and post-dispose behavior tests for . public partial class CombineLatest15ObservableTests { - /// - /// Verifies that disposing twice does not throw an exception. - /// + /// Verifies that disposing twice does not throw an exception. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Dispose_CalledTwice_NoException() { @@ -41,23 +33,17 @@ public async Task Dispose_CalledTwice_NoException() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); - var subscription = combined.Subscribe(new AnonymousObserver(_ => { }, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(static _ => { }, static _ => { }, static () => { })); subscription.Dispose(); subscription.Dispose(); await Assert.That(subscription.GetType()).IsNotNull(); } - /// - /// Verifies that a source emitting after dispose does not throw. - /// + /// Verifies that a source emitting after dispose does not throw. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task SourceEmitsAfterDispose_NoException() { @@ -92,10 +78,10 @@ public async Task SourceEmitsAfterDispose_NoException() source13, source14, source15, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); var results = new List(); - var subscription = combined.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); source1.OnNext(1); source2.OnNext(1); @@ -119,14 +105,8 @@ public async Task SourceEmitsAfterDispose_NoException() await Assert.That(results).Count().IsEqualTo(1); } - /// - /// Verifies that an error after dispose is ignored. - /// + /// Verifies that an error after dispose is ignored. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorAfterDispose_IsIgnored() { @@ -161,13 +141,13 @@ public async Task ErrorAfterDispose_IsIgnored() source13, source14, source15, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); subscription.Dispose(); source1.OnError(new InvalidOperationException(IgnoredErrorMessage)); @@ -194,10 +174,6 @@ public async Task ErrorAfterDispose_IsIgnored() /// when the subscription has been disposed but the observers are still reachable. /// /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorAfterDispose_AllObservers_CoverNullPath() { @@ -232,13 +208,13 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() manual13, manual14, manual15, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); // Set all has-value flags so TryEmit reaches _observer?.OnNext manual1.Observer!.OnNext(1); @@ -266,9 +242,7 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() await Assert.That(receivedError).IsNull(); } - /// - /// Emits the post-dispose sample value through each manual observer in turn. - /// + /// Emits the post-dispose sample value through each manual observer in turn. /// The manual observables to emit through, in order. private static void EmitPostDisposeValues(params ManualObservable[] observables) { @@ -284,9 +258,7 @@ private static void EmitPostDisposeValues(params ManualObservable[] observa } } - /// - /// Emits a post-dispose error that is expected to be ignored through each manual observer. - /// + /// Emits a post-dispose error that is expected to be ignored through each manual observer. /// The manual observables to emit through, in order. private static void EmitPostDisposeErrors(params ManualObservable[] observables) { diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest15ObservableTests.Emission.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest15ObservableTests.Emission.cs index 4868d36..7270ffd 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest15ObservableTests.Emission.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest15ObservableTests.Emission.cs @@ -8,19 +8,11 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Per-source error-propagation tests (part 1) for . -/// +/// Per-source error-propagation tests (part 1) for . public partial class CombineLatest15ObservableTests { - /// - /// Verifies that an error in the first source observable is propagated to the subscriber. - /// + /// Verifies that an error in the first source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource1_PropagatedToSubscriber() { @@ -55,15 +47,15 @@ public async Task ErrorInSource1_PropagatedToSubscriber() source13, source14, source15, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source1 error"); source1.OnError(expectedError); @@ -73,14 +65,8 @@ public async Task ErrorInSource1_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the second source observable is propagated to the subscriber. - /// + /// Verifies that an error in the second source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource2_PropagatedToSubscriber() { @@ -115,15 +101,15 @@ public async Task ErrorInSource2_PropagatedToSubscriber() source13, source14, source15, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source2 error"); source2.OnError(expectedError); @@ -133,14 +119,8 @@ public async Task ErrorInSource2_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the third source observable is propagated to the subscriber. - /// + /// Verifies that an error in the third source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource3_PropagatedToSubscriber() { @@ -175,15 +155,15 @@ public async Task ErrorInSource3_PropagatedToSubscriber() source13, source14, source15, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source3 error"); source3.OnError(expectedError); @@ -193,14 +173,8 @@ public async Task ErrorInSource3_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fourth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fourth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource4_PropagatedToSubscriber() { @@ -235,15 +209,15 @@ public async Task ErrorInSource4_PropagatedToSubscriber() source13, source14, source15, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source4 error"); source4.OnError(expectedError); @@ -253,14 +227,8 @@ public async Task ErrorInSource4_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fifth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fifth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource5_PropagatedToSubscriber() { @@ -295,15 +263,15 @@ public async Task ErrorInSource5_PropagatedToSubscriber() source13, source14, source15, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source5 error"); source5.OnError(expectedError); @@ -313,14 +281,8 @@ public async Task ErrorInSource5_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the sixth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the sixth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource6_PropagatedToSubscriber() { @@ -355,15 +317,15 @@ public async Task ErrorInSource6_PropagatedToSubscriber() source13, source14, source15, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source6 error"); source6.OnError(expectedError); @@ -373,14 +335,8 @@ public async Task ErrorInSource6_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the seventh source observable is propagated to the subscriber. - /// + /// Verifies that an error in the seventh source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource7_PropagatedToSubscriber() { @@ -415,15 +371,15 @@ public async Task ErrorInSource7_PropagatedToSubscriber() source13, source14, source15, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source7 error"); source7.OnError(expectedError); @@ -433,14 +389,8 @@ public async Task ErrorInSource7_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the eighth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the eighth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource8_PropagatedToSubscriber() { @@ -475,15 +425,15 @@ public async Task ErrorInSource8_PropagatedToSubscriber() source13, source14, source15, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source8 error"); source8.OnError(expectedError); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest15ObservableTests.Emission2.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest15ObservableTests.Emission2.cs index 920b268..63b052d 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest15ObservableTests.Emission2.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest15ObservableTests.Emission2.cs @@ -8,19 +8,11 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Per-source error-propagation tests (part 2) for . -/// +/// Per-source error-propagation tests (part 2) for . public partial class CombineLatest15ObservableTests { - /// - /// Verifies that an error in the ninth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the ninth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource9_PropagatedToSubscriber() { @@ -55,15 +47,15 @@ public async Task ErrorInSource9_PropagatedToSubscriber() source13, source14, source15, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source9 error"); source9.OnError(expectedError); @@ -73,14 +65,8 @@ public async Task ErrorInSource9_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the tenth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the tenth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource10_PropagatedToSubscriber() { @@ -115,15 +101,15 @@ public async Task ErrorInSource10_PropagatedToSubscriber() source13, source14, source15, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source10 error"); source10.OnError(expectedError); @@ -133,14 +119,8 @@ public async Task ErrorInSource10_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the eleventh source observable is propagated to the subscriber. - /// + /// Verifies that an error in the eleventh source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource11_PropagatedToSubscriber() { @@ -175,15 +155,15 @@ public async Task ErrorInSource11_PropagatedToSubscriber() source13, source14, source15, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source11 error"); source11.OnError(expectedError); @@ -193,14 +173,8 @@ public async Task ErrorInSource11_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the twelfth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the twelfth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource12_PropagatedToSubscriber() { @@ -235,15 +209,15 @@ public async Task ErrorInSource12_PropagatedToSubscriber() source13, source14, source15, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source12 error"); source12.OnError(expectedError); @@ -253,14 +227,8 @@ public async Task ErrorInSource12_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the thirteenth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the thirteenth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource13_PropagatedToSubscriber() { @@ -295,15 +263,15 @@ public async Task ErrorInSource13_PropagatedToSubscriber() source13, source14, source15, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source13 error"); source13.OnError(expectedError); @@ -313,14 +281,8 @@ public async Task ErrorInSource13_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fourteenth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fourteenth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource14_PropagatedToSubscriber() { @@ -355,15 +317,15 @@ public async Task ErrorInSource14_PropagatedToSubscriber() source13, source14, source15, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source14 error"); source14.OnError(expectedError); @@ -373,14 +335,8 @@ public async Task ErrorInSource14_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fifteenth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fifteenth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource15_PropagatedToSubscriber() { @@ -415,15 +371,15 @@ public async Task ErrorInSource15_PropagatedToSubscriber() source13, source14, source15, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source15 error"); source15.OnError(expectedError); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest15ObservableTests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest15ObservableTests.cs index 7021166..2aafc65 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest15ObservableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest15ObservableTests.cs @@ -8,173 +8,105 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Unit tests for edge cases. -/// +/// Unit tests for edge cases. public partial class CombineLatest15ObservableTests { - /// - /// Sample value emitted by the second source under test. - /// + /// Sample value emitted by the second source under test. private const int SampleValue2 = 2; - /// - /// Sample value emitted by the third source under test. - /// + /// Sample value emitted by the third source under test. private const int SampleValue3 = 3; - /// - /// Sample value emitted by the fourth source under test. - /// + /// Sample value emitted by the fourth source under test. private const int SampleValue4 = 4; - /// - /// Sample value emitted by the fifth source under test. - /// + /// Sample value emitted by the fifth source under test. private const int SampleValue5 = 5; - /// - /// Sample value emitted by the sixth source under test. - /// + /// Sample value emitted by the sixth source under test. private const int SampleValue6 = 6; - /// - /// Sample value emitted by the seventh source under test. - /// + /// Sample value emitted by the seventh source under test. private const int SampleValue7 = 7; - /// - /// Sample value emitted by the eighth source under test. - /// + /// Sample value emitted by the eighth source under test. private const int SampleValue8 = 8; - /// - /// Sample value emitted by the ninth source under test. - /// + /// Sample value emitted by the ninth source under test. private const int SampleValue9 = 9; - /// - /// Sample value emitted by the tenth source under test. - /// + /// Sample value emitted by the tenth source under test. private const int SampleValue10 = 10; - /// - /// Sample value emitted by the eleventh source under test. - /// + /// Sample value emitted by the eleventh source under test. private const int SampleValue11 = 11; - /// - /// Sample value emitted by the twelfth source under test. - /// + /// Sample value emitted by the twelfth source under test. private const int SampleValue12 = 12; - /// - /// Sample value emitted by the thirteenth source under test. - /// + /// Sample value emitted by the thirteenth source under test. private const int SampleValue13 = 13; - /// - /// Sample value emitted by the fourteenth source under test. - /// + /// Sample value emitted by the fourteenth source under test. private const int SampleValue14 = 14; - /// - /// Sample value emitted by the fifteenth source under test. - /// + /// Sample value emitted by the fifteenth source under test. private const int SampleValue15 = 15; - /// - /// Sample value emitted by the first source after the subscription is disposed. - /// + /// Sample value emitted by the first source after the subscription is disposed. private const int PostDisposeValue1 = 10; - /// - /// Sample value emitted by the second source after the subscription is disposed. - /// + /// Sample value emitted by the second source after the subscription is disposed. private const int PostDisposeValue2 = 20; - /// - /// Sample value emitted by the third source after the subscription is disposed. - /// + /// Sample value emitted by the third source after the subscription is disposed. private const int PostDisposeValue3 = 30; - /// - /// Sample value emitted by the fourth source after the subscription is disposed. - /// + /// Sample value emitted by the fourth source after the subscription is disposed. private const int PostDisposeValue4 = 40; - /// - /// Sample value emitted by the fifth source after the subscription is disposed. - /// + /// Sample value emitted by the fifth source after the subscription is disposed. private const int PostDisposeValue5 = 50; - /// - /// Sample value emitted by the sixth source after the subscription is disposed. - /// + /// Sample value emitted by the sixth source after the subscription is disposed. private const int PostDisposeValue6 = 60; - /// - /// Sample value emitted by the seventh source after the subscription is disposed. - /// + /// Sample value emitted by the seventh source after the subscription is disposed. private const int PostDisposeValue7 = 70; - /// - /// Sample value emitted by the eighth source after the subscription is disposed. - /// + /// Sample value emitted by the eighth source after the subscription is disposed. private const int PostDisposeValue8 = 80; - /// - /// Sample value emitted by the ninth source after the subscription is disposed. - /// + /// Sample value emitted by the ninth source after the subscription is disposed. private const int PostDisposeValue9 = 90; - /// - /// Sample value emitted by the tenth source after the subscription is disposed. - /// + /// Sample value emitted by the tenth source after the subscription is disposed. private const int PostDisposeValue10 = 100; - /// - /// Sample value emitted by the eleventh source after the subscription is disposed. - /// + /// Sample value emitted by the eleventh source after the subscription is disposed. private const int PostDisposeValue11 = 110; - /// - /// Sample value emitted by the twelfth source after the subscription is disposed. - /// + /// Sample value emitted by the twelfth source after the subscription is disposed. private const int PostDisposeValue12 = 120; - /// - /// Sample value emitted by the thirteenth source after the subscription is disposed. - /// + /// Sample value emitted by the thirteenth source after the subscription is disposed. private const int PostDisposeValue13 = 130; - /// - /// Sample value emitted by the fourteenth source after the subscription is disposed. - /// + /// Sample value emitted by the fourteenth source after the subscription is disposed. private const int PostDisposeValue14 = 140; - /// - /// Sample value emitted by the fifteenth source after the subscription is disposed. - /// + /// Sample value emitted by the fifteenth source after the subscription is disposed. private const int PostDisposeValue15 = 150; - /// - /// The message used for errors that are expected to be ignored after disposal. - /// + /// The message used for errors that are expected to be ignored after disposal. private const string IgnoredErrorMessage = "should be ignored"; - /// - /// Verifies that a null first source throws . - /// + /// Verifies that a null first source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource1_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( (IObservable)null!, new Subject(), new Subject(), @@ -190,23 +122,17 @@ public async Task Constructor_NullSource1_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null second source throws . - /// + /// Verifies that a null second source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource2_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), (IObservable)null!, new Subject(), @@ -222,23 +148,17 @@ public async Task Constructor_NullSource2_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null third source throws . - /// + /// Verifies that a null third source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource3_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), (IObservable)null!, @@ -254,23 +174,17 @@ public async Task Constructor_NullSource3_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fourth source throws . - /// + /// Verifies that a null fourth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource4_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -286,23 +200,17 @@ public async Task Constructor_NullSource4_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fifth source throws . - /// + /// Verifies that a null fifth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource5_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -318,23 +226,17 @@ public async Task Constructor_NullSource5_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null sixth source throws . - /// + /// Verifies that a null sixth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource6_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -350,23 +252,17 @@ public async Task Constructor_NullSource6_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null seventh source throws . - /// + /// Verifies that a null seventh source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource7_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -382,23 +278,17 @@ public async Task Constructor_NullSource7_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null eighth source throws . - /// + /// Verifies that a null eighth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource8_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -414,23 +304,17 @@ public async Task Constructor_NullSource8_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null ninth source throws . - /// + /// Verifies that a null ninth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource9_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -446,23 +330,17 @@ public async Task Constructor_NullSource9_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null tenth source throws . - /// + /// Verifies that a null tenth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource10_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -478,23 +356,17 @@ public async Task Constructor_NullSource10_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null eleventh source throws . - /// + /// Verifies that a null eleventh source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource11_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -510,23 +382,17 @@ public async Task Constructor_NullSource11_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null twelfth source throws . - /// + /// Verifies that a null twelfth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource12_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -542,23 +408,17 @@ public async Task Constructor_NullSource12_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null thirteenth source throws . - /// + /// Verifies that a null thirteenth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource13_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -574,23 +434,17 @@ public async Task Constructor_NullSource13_Throws() (IObservable)null!, new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fourteenth source throws . - /// + /// Verifies that a null fourteenth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource14_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -606,23 +460,17 @@ public async Task Constructor_NullSource14_Throws() new Subject(), (IObservable)null!, new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fifteenth source throws . - /// + /// Verifies that a null fifteenth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource15_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -638,23 +486,17 @@ public async Task Constructor_NullSource15_Throws() new Subject(), new Subject(), (IObservable)null!, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null result selector throws . - /// + /// Verifies that a null result selector throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullResultSelector_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -675,14 +517,8 @@ public async Task Constructor_NullResultSelector_Throws() await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that subscribing with a null observer throws . - /// + /// Verifies that subscribing with a null observer throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Subscribe_NullObserver_Throws() { @@ -702,22 +538,19 @@ public async Task Subscribe_NullObserver_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o); var act = () => combined.Subscribe(null!); await Assert.That(act).ThrowsExactly(); } - /// - /// A simple observer implementation that delegates to provided action callbacks. - /// + /// A simple observer implementation that delegates to provided action callbacks. /// The type of elements observed. /// The action to invoke for each observed element. /// The action to invoke when an error occurs. /// The action to invoke when the sequence completes. - private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) - : IObserver + private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) : IObserver { /// public void OnCompleted() => onCompleted(); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest16ObservableTests.Completion.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest16ObservableTests.Completion.cs index 6f59081..87acdf8 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest16ObservableTests.Completion.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest16ObservableTests.Completion.cs @@ -8,19 +8,12 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Completion-propagation tests for . -/// +/// Completion-propagation tests for . public partial class CombineLatest16ObservableTests { - /// - /// Verifies that OnCompleted from a single source does not propagate completion. - /// + /// Verifies that OnCompleted from a single source does not propagate completion. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] + [SuppressMessage("Design", "SST1523:Methods should not be too long", Justification = "Length is intrinsic to the fixed CombineLatest arity; each source needs its own line.")] [Test] public async Task CompletedInSource_DoesNotPropagateCompletion() { @@ -57,14 +50,14 @@ public async Task CompletedInSource_DoesNotPropagateCompletion() source14, source15, source16, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); var completed = false; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, - _ => { }, + static _ => { }, () => completed = true)); source1.OnNext(1); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest16ObservableTests.Disposal.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest16ObservableTests.Disposal.cs index 395ea9a..8622043 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest16ObservableTests.Disposal.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest16ObservableTests.Disposal.cs @@ -9,19 +9,11 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Disposal and post-dispose behavior tests for . -/// +/// Disposal and post-dispose behavior tests for . public partial class CombineLatest16ObservableTests { - /// - /// Verifies that disposing twice does not throw an exception. - /// + /// Verifies that disposing twice does not throw an exception. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Dispose_CalledTwice_NoException() { @@ -42,23 +34,17 @@ public async Task Dispose_CalledTwice_NoException() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); - var subscription = combined.Subscribe(new AnonymousObserver(_ => { }, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(static _ => { }, static _ => { }, static () => { })); subscription.Dispose(); subscription.Dispose(); await Assert.That(subscription.GetType()).IsNotNull(); } - /// - /// Verifies that a source emitting after dispose does not throw. - /// + /// Verifies that a source emitting after dispose does not throw. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task SourceEmitsAfterDispose_NoException() { @@ -95,10 +81,10 @@ public async Task SourceEmitsAfterDispose_NoException() source14, source15, source16, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); var results = new List(); - var subscription = combined.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); source1.OnNext(1); source2.OnNext(1); @@ -123,14 +109,9 @@ public async Task SourceEmitsAfterDispose_NoException() await Assert.That(results).Count().IsEqualTo(1); } - /// - /// Verifies that an error after dispose is ignored. - /// + /// Verifies that an error after dispose is ignored. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] + [SuppressMessage("Design", "SST1523:Methods should not be too long", Justification = "Length is intrinsic to the fixed CombineLatest arity; each source needs its own line.")] [Test] public async Task ErrorAfterDispose_IsIgnored() { @@ -167,13 +148,13 @@ public async Task ErrorAfterDispose_IsIgnored() source14, source15, source16, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); subscription.Dispose(); source1.OnError(new InvalidOperationException(IgnoredErrorMessage)); @@ -201,10 +182,7 @@ public async Task ErrorAfterDispose_IsIgnored() /// when the subscription has been disposed but the observers are still reachable. /// /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] + [SuppressMessage("Design", "SST1523:Methods should not be too long", Justification = "Length is intrinsic to the fixed CombineLatest arity; each source needs its own line.")] [Test] public async Task ErrorAfterDispose_AllObservers_CoverNullPath() { @@ -241,13 +219,13 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() manual14, manual15, manual16, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); // Set all has-value flags so TryEmit reaches _observer?.OnNext manual1.Observer!.OnNext(1); @@ -276,9 +254,7 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() await Assert.That(receivedError).IsNull(); } - /// - /// Emits the post-dispose sample value through each manual observer in turn. - /// + /// Emits the post-dispose sample value through each manual observer in turn. /// The manual observables to emit through, in order. private static void EmitPostDisposeValues(params ManualObservable[] observables) { @@ -294,9 +270,7 @@ private static void EmitPostDisposeValues(params ManualObservable[] observa } } - /// - /// Emits a post-dispose error that is expected to be ignored through each manual observer. - /// + /// Emits a post-dispose error that is expected to be ignored through each manual observer. /// The manual observables to emit through, in order. private static void EmitPostDisposeErrors(params ManualObservable[] observables) { diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest16ObservableTests.Emission.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest16ObservableTests.Emission.cs index bc35b07..099393d 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest16ObservableTests.Emission.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest16ObservableTests.Emission.cs @@ -8,19 +8,11 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Per-source error-propagation tests (part 1) for . -/// +/// Per-source error-propagation tests (part 1) for . public partial class CombineLatest16ObservableTests { - /// - /// Verifies that an error in the first source observable is propagated to the subscriber. - /// + /// Verifies that an error in the first source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource1_PropagatedToSubscriber() { @@ -57,15 +49,15 @@ public async Task ErrorInSource1_PropagatedToSubscriber() source14, source15, source16, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source1 error"); source1.OnError(expectedError); @@ -75,14 +67,8 @@ public async Task ErrorInSource1_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the second source observable is propagated to the subscriber. - /// + /// Verifies that an error in the second source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource2_PropagatedToSubscriber() { @@ -119,15 +105,15 @@ public async Task ErrorInSource2_PropagatedToSubscriber() source14, source15, source16, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source2 error"); source2.OnError(expectedError); @@ -137,14 +123,8 @@ public async Task ErrorInSource2_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the third source observable is propagated to the subscriber. - /// + /// Verifies that an error in the third source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource3_PropagatedToSubscriber() { @@ -181,15 +161,15 @@ public async Task ErrorInSource3_PropagatedToSubscriber() source14, source15, source16, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source3 error"); source3.OnError(expectedError); @@ -199,14 +179,8 @@ public async Task ErrorInSource3_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fourth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fourth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource4_PropagatedToSubscriber() { @@ -243,15 +217,15 @@ public async Task ErrorInSource4_PropagatedToSubscriber() source14, source15, source16, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source4 error"); source4.OnError(expectedError); @@ -261,14 +235,8 @@ public async Task ErrorInSource4_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fifth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fifth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource5_PropagatedToSubscriber() { @@ -305,15 +273,15 @@ public async Task ErrorInSource5_PropagatedToSubscriber() source14, source15, source16, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source5 error"); source5.OnError(expectedError); @@ -323,14 +291,8 @@ public async Task ErrorInSource5_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the sixth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the sixth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource6_PropagatedToSubscriber() { @@ -367,15 +329,15 @@ public async Task ErrorInSource6_PropagatedToSubscriber() source14, source15, source16, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source6 error"); source6.OnError(expectedError); @@ -385,14 +347,8 @@ public async Task ErrorInSource6_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the seventh source observable is propagated to the subscriber. - /// + /// Verifies that an error in the seventh source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource7_PropagatedToSubscriber() { @@ -429,15 +385,15 @@ public async Task ErrorInSource7_PropagatedToSubscriber() source14, source15, source16, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source7 error"); source7.OnError(expectedError); @@ -447,14 +403,8 @@ public async Task ErrorInSource7_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the eighth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the eighth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource8_PropagatedToSubscriber() { @@ -491,15 +441,15 @@ public async Task ErrorInSource8_PropagatedToSubscriber() source14, source15, source16, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source8 error"); source8.OnError(expectedError); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest16ObservableTests.Emission2.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest16ObservableTests.Emission2.cs index 86faf4d..1d75ade 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest16ObservableTests.Emission2.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest16ObservableTests.Emission2.cs @@ -8,19 +8,11 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Per-source error-propagation tests (part 2) for . -/// +/// Per-source error-propagation tests (part 2) for . public partial class CombineLatest16ObservableTests { - /// - /// Verifies that an error in the ninth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the ninth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource9_PropagatedToSubscriber() { @@ -57,15 +49,15 @@ public async Task ErrorInSource9_PropagatedToSubscriber() source14, source15, source16, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source9 error"); source9.OnError(expectedError); @@ -75,14 +67,8 @@ public async Task ErrorInSource9_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the tenth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the tenth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource10_PropagatedToSubscriber() { @@ -119,15 +105,15 @@ public async Task ErrorInSource10_PropagatedToSubscriber() source14, source15, source16, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source10 error"); source10.OnError(expectedError); @@ -137,14 +123,8 @@ public async Task ErrorInSource10_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the eleventh source observable is propagated to the subscriber. - /// + /// Verifies that an error in the eleventh source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource11_PropagatedToSubscriber() { @@ -181,15 +161,15 @@ public async Task ErrorInSource11_PropagatedToSubscriber() source14, source15, source16, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source11 error"); source11.OnError(expectedError); @@ -199,14 +179,8 @@ public async Task ErrorInSource11_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the twelfth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the twelfth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource12_PropagatedToSubscriber() { @@ -243,15 +217,15 @@ public async Task ErrorInSource12_PropagatedToSubscriber() source14, source15, source16, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source12 error"); source12.OnError(expectedError); @@ -261,14 +235,8 @@ public async Task ErrorInSource12_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the thirteenth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the thirteenth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource13_PropagatedToSubscriber() { @@ -305,15 +273,15 @@ public async Task ErrorInSource13_PropagatedToSubscriber() source14, source15, source16, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source13 error"); source13.OnError(expectedError); @@ -323,14 +291,8 @@ public async Task ErrorInSource13_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fourteenth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fourteenth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource14_PropagatedToSubscriber() { @@ -367,15 +329,15 @@ public async Task ErrorInSource14_PropagatedToSubscriber() source14, source15, source16, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source14 error"); source14.OnError(expectedError); @@ -385,14 +347,8 @@ public async Task ErrorInSource14_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fifteenth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fifteenth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource15_PropagatedToSubscriber() { @@ -429,15 +385,15 @@ public async Task ErrorInSource15_PropagatedToSubscriber() source14, source15, source16, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source15 error"); source15.OnError(expectedError); @@ -447,14 +403,8 @@ public async Task ErrorInSource15_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the sixteenth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the sixteenth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource16_PropagatedToSubscriber() { @@ -491,15 +441,15 @@ public async Task ErrorInSource16_PropagatedToSubscriber() source14, source15, source16, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}-{j}-{k}-{l}-{m}-{n}-{o}-{p}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source16 error"); source16.OnError(expectedError); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest16ObservableTests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest16ObservableTests.cs index d0c6489..315f6a1 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest16ObservableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest16ObservableTests.cs @@ -8,183 +8,111 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Unit tests for edge cases. -/// +/// Unit tests for edge cases. public partial class CombineLatest16ObservableTests { - /// - /// Sample value emitted by the second source under test. - /// + /// Sample value emitted by the second source under test. private const int SampleValue2 = 2; - /// - /// Sample value emitted by the third source under test. - /// + /// Sample value emitted by the third source under test. private const int SampleValue3 = 3; - /// - /// Sample value emitted by the fourth source under test. - /// + /// Sample value emitted by the fourth source under test. private const int SampleValue4 = 4; - /// - /// Sample value emitted by the fifth source under test. - /// + /// Sample value emitted by the fifth source under test. private const int SampleValue5 = 5; - /// - /// Sample value emitted by the sixth source under test. - /// + /// Sample value emitted by the sixth source under test. private const int SampleValue6 = 6; - /// - /// Sample value emitted by the seventh source under test. - /// + /// Sample value emitted by the seventh source under test. private const int SampleValue7 = 7; - /// - /// Sample value emitted by the eighth source under test. - /// + /// Sample value emitted by the eighth source under test. private const int SampleValue8 = 8; - /// - /// Sample value emitted by the ninth source under test. - /// + /// Sample value emitted by the ninth source under test. private const int SampleValue9 = 9; - /// - /// Sample value emitted by the tenth source under test. - /// + /// Sample value emitted by the tenth source under test. private const int SampleValue10 = 10; - /// - /// Sample value emitted by the eleventh source under test. - /// + /// Sample value emitted by the eleventh source under test. private const int SampleValue11 = 11; - /// - /// Sample value emitted by the twelfth source under test. - /// + /// Sample value emitted by the twelfth source under test. private const int SampleValue12 = 12; - /// - /// Sample value emitted by the thirteenth source under test. - /// + /// Sample value emitted by the thirteenth source under test. private const int SampleValue13 = 13; - /// - /// Sample value emitted by the fourteenth source under test. - /// + /// Sample value emitted by the fourteenth source under test. private const int SampleValue14 = 14; - /// - /// Sample value emitted by the fifteenth source under test. - /// + /// Sample value emitted by the fifteenth source under test. private const int SampleValue15 = 15; - /// - /// Sample value emitted by the sixteenth source under test. - /// + /// Sample value emitted by the sixteenth source under test. private const int SampleValue16 = 16; - /// - /// Sample value emitted by the first source after the subscription is disposed. - /// + /// Sample value emitted by the first source after the subscription is disposed. private const int PostDisposeValue1 = 10; - /// - /// Sample value emitted by the second source after the subscription is disposed. - /// + /// Sample value emitted by the second source after the subscription is disposed. private const int PostDisposeValue2 = 20; - /// - /// Sample value emitted by the third source after the subscription is disposed. - /// + /// Sample value emitted by the third source after the subscription is disposed. private const int PostDisposeValue3 = 30; - /// - /// Sample value emitted by the fourth source after the subscription is disposed. - /// + /// Sample value emitted by the fourth source after the subscription is disposed. private const int PostDisposeValue4 = 40; - /// - /// Sample value emitted by the fifth source after the subscription is disposed. - /// + /// Sample value emitted by the fifth source after the subscription is disposed. private const int PostDisposeValue5 = 50; - /// - /// Sample value emitted by the sixth source after the subscription is disposed. - /// + /// Sample value emitted by the sixth source after the subscription is disposed. private const int PostDisposeValue6 = 60; - /// - /// Sample value emitted by the seventh source after the subscription is disposed. - /// + /// Sample value emitted by the seventh source after the subscription is disposed. private const int PostDisposeValue7 = 70; - /// - /// Sample value emitted by the eighth source after the subscription is disposed. - /// + /// Sample value emitted by the eighth source after the subscription is disposed. private const int PostDisposeValue8 = 80; - /// - /// Sample value emitted by the ninth source after the subscription is disposed. - /// + /// Sample value emitted by the ninth source after the subscription is disposed. private const int PostDisposeValue9 = 90; - /// - /// Sample value emitted by the tenth source after the subscription is disposed. - /// + /// Sample value emitted by the tenth source after the subscription is disposed. private const int PostDisposeValue10 = 100; - /// - /// Sample value emitted by the eleventh source after the subscription is disposed. - /// + /// Sample value emitted by the eleventh source after the subscription is disposed. private const int PostDisposeValue11 = 110; - /// - /// Sample value emitted by the twelfth source after the subscription is disposed. - /// + /// Sample value emitted by the twelfth source after the subscription is disposed. private const int PostDisposeValue12 = 120; - /// - /// Sample value emitted by the thirteenth source after the subscription is disposed. - /// + /// Sample value emitted by the thirteenth source after the subscription is disposed. private const int PostDisposeValue13 = 130; - /// - /// Sample value emitted by the fourteenth source after the subscription is disposed. - /// + /// Sample value emitted by the fourteenth source after the subscription is disposed. private const int PostDisposeValue14 = 140; - /// - /// Sample value emitted by the fifteenth source after the subscription is disposed. - /// + /// Sample value emitted by the fifteenth source after the subscription is disposed. private const int PostDisposeValue15 = 150; - /// - /// Sample value emitted by the sixteenth source after the subscription is disposed. - /// + /// Sample value emitted by the sixteenth source after the subscription is disposed. private const int PostDisposeValue16 = 160; - /// - /// The message used for errors that are expected to be ignored after disposal. - /// + /// The message used for errors that are expected to be ignored after disposal. private const string IgnoredErrorMessage = "should be ignored"; - /// - /// Verifies that a null first source throws . - /// + /// Verifies that a null first source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource1_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( (IObservable)null!, new Subject(), new Subject(), @@ -201,23 +129,17 @@ public async Task Constructor_NullSource1_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null second source throws . - /// + /// Verifies that a null second source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource2_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), (IObservable)null!, new Subject(), @@ -234,23 +156,17 @@ public async Task Constructor_NullSource2_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null third source throws . - /// + /// Verifies that a null third source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource3_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), (IObservable)null!, @@ -267,23 +183,17 @@ public async Task Constructor_NullSource3_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fourth source throws . - /// + /// Verifies that a null fourth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource4_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -300,23 +210,17 @@ public async Task Constructor_NullSource4_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fifth source throws . - /// + /// Verifies that a null fifth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource5_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -333,23 +237,17 @@ public async Task Constructor_NullSource5_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null sixth source throws . - /// + /// Verifies that a null sixth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource6_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -366,23 +264,17 @@ public async Task Constructor_NullSource6_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null seventh source throws . - /// + /// Verifies that a null seventh source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource7_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -399,23 +291,17 @@ public async Task Constructor_NullSource7_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null eighth source throws . - /// + /// Verifies that a null eighth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource8_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -432,23 +318,17 @@ public async Task Constructor_NullSource8_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null ninth source throws . - /// + /// Verifies that a null ninth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource9_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -465,23 +345,17 @@ public async Task Constructor_NullSource9_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null tenth source throws . - /// + /// Verifies that a null tenth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource10_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -498,23 +372,17 @@ public async Task Constructor_NullSource10_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null eleventh source throws . - /// + /// Verifies that a null eleventh source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource11_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -531,23 +399,17 @@ public async Task Constructor_NullSource11_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null twelfth source throws . - /// + /// Verifies that a null twelfth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource12_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -564,23 +426,17 @@ public async Task Constructor_NullSource12_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null thirteenth source throws . - /// + /// Verifies that a null thirteenth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource13_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -597,23 +453,17 @@ public async Task Constructor_NullSource13_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fourteenth source throws . - /// + /// Verifies that a null fourteenth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource14_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -630,23 +480,17 @@ public async Task Constructor_NullSource14_Throws() (IObservable)null!, new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fifteenth source throws . - /// + /// Verifies that a null fifteenth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource15_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -663,23 +507,17 @@ public async Task Constructor_NullSource15_Throws() new Subject(), (IObservable)null!, new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null sixteenth source throws . - /// + /// Verifies that a null sixteenth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource16_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -696,23 +534,17 @@ public async Task Constructor_NullSource16_Throws() new Subject(), new Subject(), (IObservable)null!, - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null result selector throws . - /// + /// Verifies that a null result selector throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullResultSelector_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -734,14 +566,8 @@ public async Task Constructor_NullResultSelector_Throws() await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that subscribing with a null observer throws . - /// + /// Verifies that subscribing with a null observer throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Subscribe_NullObserver_Throws() { @@ -762,22 +588,19 @@ public async Task Subscribe_NullObserver_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); + static (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p); var act = () => combined.Subscribe(null!); await Assert.That(act).ThrowsExactly(); } - /// - /// A simple observer implementation that delegates to provided action callbacks. - /// + /// A simple observer implementation that delegates to provided action callbacks. /// The type of elements observed. /// The action to invoke for each observed element. /// The action to invoke when an error occurs. /// The action to invoke when the sequence completes. - private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) - : IObserver + private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) : IObserver { /// public void OnCompleted() => onCompleted(); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest2ObservableTests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest2ObservableTests.cs index 177d494..09fa258 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest2ObservableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest2ObservableTests.cs @@ -8,9 +8,7 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Unit tests for edge cases. -/// +/// Unit tests for edge cases. public class CombineLatest2ObservableTests { /// The value emitted by the first source on the initial round. @@ -34,44 +32,38 @@ public class CombineLatest2ObservableTests /// The message used for errors that are expected to be ignored. private const string IgnoredErrorMessage = "should be ignored"; - /// - /// Verifies that a null first source throws . - /// + /// Verifies that a null first source throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource1_Throws() { - var act = () => new CombineLatest2Observable( + var act = static () => new CombineLatest2Observable( null!, new Subject(), - (a, b) => a + b); + static (a, b) => a + b); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null second source throws . - /// + /// Verifies that a null second source throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource2_Throws() { - var act = () => new CombineLatest2Observable( + var act = static () => new CombineLatest2Observable( new Subject(), null!, - (a, b) => a + b); + static (a, b) => a + b); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null result selector throws . - /// + /// Verifies that a null result selector throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullResultSelector_Throws() { - var act = () => new CombineLatest2Observable( + var act = static () => new CombineLatest2Observable( new Subject(), new Subject(), null!); @@ -79,9 +71,7 @@ public async Task Constructor_NullResultSelector_Throws() await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that subscribing with a null observer throws . - /// + /// Verifies that subscribing with a null observer throws . /// A representing the asynchronous unit test. [Test] public async Task Subscribe_NullObserver_Throws() @@ -89,16 +79,14 @@ public async Task Subscribe_NullObserver_Throws() var combined = new CombineLatest2Observable( new Subject(), new Subject(), - (a, b) => a + b); + static (a, b) => a + b); var act = () => combined.Subscribe(null!); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that disposing twice does not throw an exception. - /// + /// Verifies that disposing twice does not throw an exception. /// A representing the asynchronous unit test. [Test] public async Task Dispose_CalledTwice_NoException() @@ -106,18 +94,16 @@ public async Task Dispose_CalledTwice_NoException() var combined = new CombineLatest2Observable( new Subject(), new Subject(), - (a, b) => a + b); + static (a, b) => a + b); - var subscription = combined.Subscribe(new AnonymousObserver(_ => { }, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(static _ => { }, static _ => { }, static () => { })); subscription.Dispose(); subscription.Dispose(); await Assert.That(subscription.GetType()).IsNotNull(); } - /// - /// Verifies that a source emitting after dispose does not throw. - /// + /// Verifies that a source emitting after dispose does not throw. /// A representing the asynchronous unit test. [Test] public async Task SourceEmitsAfterDispose_NoException() @@ -127,10 +113,10 @@ public async Task SourceEmitsAfterDispose_NoException() var combined = new CombineLatest2Observable( source1, source2, - (a, b) => a + b); + static (a, b) => a + b); var results = new List(); - var subscription = combined.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); source1.OnNext(FirstValue); source2.OnNext(SecondValue); @@ -143,9 +129,7 @@ public async Task SourceEmitsAfterDispose_NoException() await Assert.That(results[0]).IsEqualTo(ExpectedSum); } - /// - /// Verifies that an error after dispose is ignored. - /// + /// Verifies that an error after dispose is ignored. /// A representing the asynchronous unit test. [Test] public async Task ErrorAfterDispose_IsIgnored() @@ -155,13 +139,13 @@ public async Task ErrorAfterDispose_IsIgnored() var combined = new CombineLatest2Observable( source1, source2, - (a, b) => a + b); + static (a, b) => a + b); Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); subscription.Dispose(); source1.OnError(new InvalidOperationException(IgnoredErrorMessage)); @@ -183,13 +167,13 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() var combined = new CombineLatest2Observable( manual1, manual2, - (a, b) => a + b); + static (a, b) => a + b); Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); // Set all has-value flags so TryEmit reaches _observer?.OnNext manual1.Observer!.OnNext(FirstValue); @@ -206,9 +190,7 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() await Assert.That(receivedError).IsNull(); } - /// - /// Verifies that an error in the first source observable is propagated to the subscriber. - /// + /// Verifies that an error in the first source observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task ErrorInFirstSource_PropagatedToSubscriber() @@ -218,15 +200,15 @@ public async Task ErrorInFirstSource_PropagatedToSubscriber() var combined = new CombineLatest2Observable( source1, source2, - (a, b) => $"{a}-{b}"); + static (a, b) => $"{a}-{b}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source1 error"); source1.OnError(expectedError); @@ -236,9 +218,7 @@ public async Task ErrorInFirstSource_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the second source observable is propagated to the subscriber. - /// + /// Verifies that an error in the second source observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task ErrorInSecondSource_PropagatedToSubscriber() @@ -248,15 +228,15 @@ public async Task ErrorInSecondSource_PropagatedToSubscriber() var combined = new CombineLatest2Observable( source1, source2, - (a, b) => $"{a}-{b}"); + static (a, b) => $"{a}-{b}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source2 error"); source2.OnError(expectedError); @@ -266,9 +246,7 @@ public async Task ErrorInSecondSource_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that OnCompleted from a single source does not propagate completion. - /// + /// Verifies that OnCompleted from a single source does not propagate completion. /// A representing the asynchronous unit test. [Test] public async Task CompletedInSource_DoesNotPropagateCompletion() @@ -278,14 +256,14 @@ public async Task CompletedInSource_DoesNotPropagateCompletion() var combined = new CombineLatest2Observable( source1, source2, - (a, b) => $"{a}-{b}"); + static (a, b) => $"{a}-{b}"); var completed = false; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, - _ => { }, + static _ => { }, () => completed = true)); source1.OnNext(FirstValue); @@ -298,15 +276,12 @@ public async Task CompletedInSource_DoesNotPropagateCompletion() await Assert.That(results).Count().IsEqualTo(ExpectedEmissionCount); } - /// - /// A simple observer implementation that delegates to provided action callbacks. - /// + /// A simple observer implementation that delegates to provided action callbacks. /// The type of elements observed. /// The action to invoke for each observed element. /// The action to invoke when an error occurs. /// The action to invoke when the sequence completes. - private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) - : IObserver + private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) : IObserver { /// public void OnCompleted() => onCompleted(); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest3ObservableTests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest3ObservableTests.cs index bc9de85..5a82bb7 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest3ObservableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest3ObservableTests.cs @@ -8,9 +8,7 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Unit tests for edge cases. -/// +/// Unit tests for edge cases. public class CombineLatest3ObservableTests { /// The value emitted by the first source on the initial round. @@ -40,62 +38,54 @@ public class CombineLatest3ObservableTests /// The message used for errors that are expected to be ignored. private const string IgnoredErrorMessage = "should be ignored"; - /// - /// Verifies that a null first source throws . - /// + /// Verifies that a null first source throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource1_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( (IObservable)null!, new Subject(), new Subject(), - (a, b, c) => a + b + c); + static (a, b, c) => a + b + c); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null second source throws . - /// + /// Verifies that a null second source throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource2_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), (IObservable)null!, new Subject(), - (a, b, c) => a + b + c); + static (a, b, c) => a + b + c); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null third source throws . - /// + /// Verifies that a null third source throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource3_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), (IObservable)null!, - (a, b, c) => a + b + c); + static (a, b, c) => a + b + c); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null result selector throws . - /// + /// Verifies that a null result selector throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullResultSelector_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -104,9 +94,7 @@ public async Task Constructor_NullResultSelector_Throws() await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that subscribing with a null observer throws . - /// + /// Verifies that subscribing with a null observer throws . /// A representing the asynchronous unit test. [Test] public async Task Subscribe_NullObserver_Throws() @@ -115,16 +103,14 @@ public async Task Subscribe_NullObserver_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c) => a + b + c); + static (a, b, c) => a + b + c); var act = () => combined.Subscribe(null!); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that disposing twice does not throw an exception. - /// + /// Verifies that disposing twice does not throw an exception. /// A representing the asynchronous unit test. [Test] public async Task Dispose_CalledTwice_NoException() @@ -133,18 +119,16 @@ public async Task Dispose_CalledTwice_NoException() new Subject(), new Subject(), new Subject(), - (a, b, c) => a + b + c); + static (a, b, c) => a + b + c); - var subscription = combined.Subscribe(new AnonymousObserver(_ => { }, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(static _ => { }, static _ => { }, static () => { })); subscription.Dispose(); subscription.Dispose(); await Assert.That(subscription.GetType()).IsNotNull(); } - /// - /// Verifies that a source emitting after dispose does not throw. - /// + /// Verifies that a source emitting after dispose does not throw. /// A representing the asynchronous unit test. [Test] public async Task SourceEmitsAfterDispose_NoException() @@ -156,10 +140,10 @@ public async Task SourceEmitsAfterDispose_NoException() source1, source2, source3, - (a, b, c) => a + b + c); + static (a, b, c) => a + b + c); var results = new List(); - var subscription = combined.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); source1.OnNext(FirstValue); source2.OnNext(SecondValue); @@ -174,9 +158,7 @@ public async Task SourceEmitsAfterDispose_NoException() await Assert.That(results[0]).IsEqualTo(ExpectedSum); } - /// - /// Verifies that an error after dispose is ignored. - /// + /// Verifies that an error after dispose is ignored. /// A representing the asynchronous unit test. [Test] public async Task ErrorAfterDispose_IsIgnored() @@ -188,13 +170,13 @@ public async Task ErrorAfterDispose_IsIgnored() source1, source2, source3, - (a, b, c) => a + b + c); + static (a, b, c) => a + b + c); Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); subscription.Dispose(); source1.OnError(new InvalidOperationException(IgnoredErrorMessage)); @@ -219,13 +201,13 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() manual1, manual2, manual3, - (a, b, c) => a + b + c); + static (a, b, c) => a + b + c); Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); // Set all has-value flags so TryEmit reaches _observer?.OnNext manual1.Observer!.OnNext(FirstValue); @@ -245,9 +227,7 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() await Assert.That(receivedError).IsNull(); } - /// - /// Verifies that an error in the first source observable is propagated to the subscriber. - /// + /// Verifies that an error in the first source observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task ErrorInSource1_PropagatedToSubscriber() @@ -259,15 +239,15 @@ public async Task ErrorInSource1_PropagatedToSubscriber() source1, source2, source3, - (a, b, c) => $"{a}-{b}-{c}"); + static (a, b, c) => $"{a}-{b}-{c}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source1 error"); source1.OnError(expectedError); @@ -277,9 +257,7 @@ public async Task ErrorInSource1_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the second source observable is propagated to the subscriber. - /// + /// Verifies that an error in the second source observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task ErrorInSource2_PropagatedToSubscriber() @@ -291,15 +269,15 @@ public async Task ErrorInSource2_PropagatedToSubscriber() source1, source2, source3, - (a, b, c) => $"{a}-{b}-{c}"); + static (a, b, c) => $"{a}-{b}-{c}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source2 error"); source2.OnError(expectedError); @@ -309,9 +287,7 @@ public async Task ErrorInSource2_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the third source observable is propagated to the subscriber. - /// + /// Verifies that an error in the third source observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task ErrorInSource3_PropagatedToSubscriber() @@ -323,15 +299,15 @@ public async Task ErrorInSource3_PropagatedToSubscriber() source1, source2, source3, - (a, b, c) => $"{a}-{b}-{c}"); + static (a, b, c) => $"{a}-{b}-{c}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source3 error"); source3.OnError(expectedError); @@ -341,9 +317,7 @@ public async Task ErrorInSource3_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that OnCompleted from a single source does not propagate completion. - /// + /// Verifies that OnCompleted from a single source does not propagate completion. /// A representing the asynchronous unit test. [Test] public async Task CompletedInSource_DoesNotPropagateCompletion() @@ -355,14 +329,14 @@ public async Task CompletedInSource_DoesNotPropagateCompletion() source1, source2, source3, - (a, b, c) => $"{a}-{b}-{c}"); + static (a, b, c) => $"{a}-{b}-{c}"); var completed = false; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, - _ => { }, + static _ => { }, () => completed = true)); source1.OnNext(FirstValue); @@ -377,15 +351,12 @@ public async Task CompletedInSource_DoesNotPropagateCompletion() await Assert.That(results).Count().IsEqualTo(ExpectedEmissionCount); } - /// - /// A simple observer implementation that delegates to provided action callbacks. - /// + /// A simple observer implementation that delegates to provided action callbacks. /// The type of elements observed. /// The action to invoke for each observed element. /// The action to invoke when an error occurs. /// The action to invoke when the sequence completes. - private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) - : IObserver + private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) : IObserver { /// public void OnCompleted() => onCompleted(); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest4ObservableTests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest4ObservableTests.cs index ef7eb33..3ec6ef6 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest4ObservableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest4ObservableTests.cs @@ -8,9 +8,7 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Unit tests for edge cases. -/// +/// Unit tests for edge cases. public class CombineLatest4ObservableTests { /// The value emitted by the first source on the initial round. @@ -46,82 +44,72 @@ public class CombineLatest4ObservableTests /// The message used for errors that are expected to be ignored. private const string IgnoredErrorMessage = "should be ignored"; - /// - /// Verifies that a null first source throws . - /// + /// Verifies that a null first source throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource1_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( (IObservable)null!, new Subject(), new Subject(), new Subject(), - (a, b, c, d) => a + b + c + d); + static (a, b, c, d) => a + b + c + d); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null second source throws . - /// + /// Verifies that a null second source throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource2_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), (IObservable)null!, new Subject(), new Subject(), - (a, b, c, d) => a + b + c + d); + static (a, b, c, d) => a + b + c + d); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null third source throws . - /// + /// Verifies that a null third source throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource3_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), (IObservable)null!, new Subject(), - (a, b, c, d) => a + b + c + d); + static (a, b, c, d) => a + b + c + d); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fourth source throws . - /// + /// Verifies that a null fourth source throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource4_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), (IObservable)null!, - (a, b, c, d) => a + b + c + d); + static (a, b, c, d) => a + b + c + d); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null result selector throws . - /// + /// Verifies that a null result selector throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullResultSelector_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -131,9 +119,7 @@ public async Task Constructor_NullResultSelector_Throws() await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that subscribing with a null observer throws . - /// + /// Verifies that subscribing with a null observer throws . /// A representing the asynchronous unit test. [Test] public async Task Subscribe_NullObserver_Throws() @@ -143,16 +129,14 @@ public async Task Subscribe_NullObserver_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d) => a + b + c + d); + static (a, b, c, d) => a + b + c + d); var act = () => combined.Subscribe(null!); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that disposing twice does not throw an exception. - /// + /// Verifies that disposing twice does not throw an exception. /// A representing the asynchronous unit test. [Test] public async Task Dispose_CalledTwice_NoException() @@ -162,18 +146,16 @@ public async Task Dispose_CalledTwice_NoException() new Subject(), new Subject(), new Subject(), - (a, b, c, d) => a + b + c + d); + static (a, b, c, d) => a + b + c + d); - var subscription = combined.Subscribe(new AnonymousObserver(_ => { }, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(static _ => { }, static _ => { }, static () => { })); subscription.Dispose(); subscription.Dispose(); await Assert.That(subscription.GetType()).IsNotNull(); } - /// - /// Verifies that a source emitting after dispose does not throw. - /// + /// Verifies that a source emitting after dispose does not throw. /// A representing the asynchronous unit test. [Test] public async Task SourceEmitsAfterDispose_NoException() @@ -187,10 +169,10 @@ public async Task SourceEmitsAfterDispose_NoException() source2, source3, source4, - (a, b, c, d) => a + b + c + d); + static (a, b, c, d) => a + b + c + d); var results = new List(); - var subscription = combined.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); source1.OnNext(FirstValue); source2.OnNext(SecondValue); @@ -207,9 +189,7 @@ public async Task SourceEmitsAfterDispose_NoException() await Assert.That(results[0]).IsEqualTo(ExpectedSum); } - /// - /// Verifies that an error after dispose is ignored. - /// + /// Verifies that an error after dispose is ignored. /// A representing the asynchronous unit test. [Test] public async Task ErrorAfterDispose_IsIgnored() @@ -223,13 +203,13 @@ public async Task ErrorAfterDispose_IsIgnored() source2, source3, source4, - (a, b, c, d) => a + b + c + d); + static (a, b, c, d) => a + b + c + d); Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); subscription.Dispose(); source1.OnError(new InvalidOperationException(IgnoredErrorMessage)); @@ -257,13 +237,13 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() manual2, manual3, manual4, - (a, b, c, d) => a + b + c + d); + static (a, b, c, d) => a + b + c + d); Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); // Set all has-value flags so TryEmit reaches _observer?.OnNext manual1.Observer!.OnNext(FirstValue); @@ -286,9 +266,7 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() await Assert.That(receivedError).IsNull(); } - /// - /// Verifies that an error in the first source observable is propagated to the subscriber. - /// + /// Verifies that an error in the first source observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task ErrorInSource1_PropagatedToSubscriber() @@ -302,15 +280,15 @@ public async Task ErrorInSource1_PropagatedToSubscriber() source2, source3, source4, - (a, b, c, d) => $"{a}-{b}-{c}-{d}"); + static (a, b, c, d) => $"{a}-{b}-{c}-{d}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source1 error"); source1.OnError(expectedError); @@ -320,9 +298,7 @@ public async Task ErrorInSource1_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the second source observable is propagated to the subscriber. - /// + /// Verifies that an error in the second source observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task ErrorInSource2_PropagatedToSubscriber() @@ -336,15 +312,15 @@ public async Task ErrorInSource2_PropagatedToSubscriber() source2, source3, source4, - (a, b, c, d) => $"{a}-{b}-{c}-{d}"); + static (a, b, c, d) => $"{a}-{b}-{c}-{d}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source2 error"); source2.OnError(expectedError); @@ -354,9 +330,7 @@ public async Task ErrorInSource2_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the third source observable is propagated to the subscriber. - /// + /// Verifies that an error in the third source observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task ErrorInSource3_PropagatedToSubscriber() @@ -370,15 +344,15 @@ public async Task ErrorInSource3_PropagatedToSubscriber() source2, source3, source4, - (a, b, c, d) => $"{a}-{b}-{c}-{d}"); + static (a, b, c, d) => $"{a}-{b}-{c}-{d}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source3 error"); source3.OnError(expectedError); @@ -388,9 +362,7 @@ public async Task ErrorInSource3_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fourth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fourth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task ErrorInSource4_PropagatedToSubscriber() @@ -404,15 +376,15 @@ public async Task ErrorInSource4_PropagatedToSubscriber() source2, source3, source4, - (a, b, c, d) => $"{a}-{b}-{c}-{d}"); + static (a, b, c, d) => $"{a}-{b}-{c}-{d}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source4 error"); source4.OnError(expectedError); @@ -422,9 +394,7 @@ public async Task ErrorInSource4_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that OnCompleted from a single source does not propagate completion. - /// + /// Verifies that OnCompleted from a single source does not propagate completion. /// A representing the asynchronous unit test. [Test] public async Task CompletedInSource_DoesNotPropagateCompletion() @@ -438,14 +408,14 @@ public async Task CompletedInSource_DoesNotPropagateCompletion() source2, source3, source4, - (a, b, c, d) => $"{a}-{b}-{c}-{d}"); + static (a, b, c, d) => $"{a}-{b}-{c}-{d}"); var completed = false; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, - _ => { }, + static _ => { }, () => completed = true)); source1.OnNext(FirstValue); @@ -462,15 +432,12 @@ public async Task CompletedInSource_DoesNotPropagateCompletion() await Assert.That(results).Count().IsEqualTo(ExpectedEmissionCount); } - /// - /// A simple observer implementation that delegates to provided action callbacks. - /// + /// A simple observer implementation that delegates to provided action callbacks. /// The type of elements observed. /// The action to invoke for each observed element. /// The action to invoke when an error occurs. /// The action to invoke when the sequence completes. - private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) - : IObserver + private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) : IObserver { /// public void OnCompleted() => onCompleted(); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest5ObservableTests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest5ObservableTests.cs index cea59bb..b2eba8b 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest5ObservableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest5ObservableTests.cs @@ -8,9 +8,7 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Unit tests for edge cases. -/// +/// Unit tests for edge cases. public class CombineLatest5ObservableTests { /// The value emitted by the first source on the initial round. @@ -52,104 +50,92 @@ public class CombineLatest5ObservableTests /// The message used for errors that are expected to be ignored. private const string IgnoredErrorMessage = "should be ignored"; - /// - /// Verifies that a null first source throws . - /// + /// Verifies that a null first source throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource1_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( (IObservable)null!, new Subject(), new Subject(), new Subject(), new Subject(), - (a, b, c, d, e) => a + b + c + d + e); + static (a, b, c, d, e) => a + b + c + d + e); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null second source throws . - /// + /// Verifies that a null second source throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource2_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), (IObservable)null!, new Subject(), new Subject(), new Subject(), - (a, b, c, d, e) => a + b + c + d + e); + static (a, b, c, d, e) => a + b + c + d + e); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null third source throws . - /// + /// Verifies that a null third source throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource3_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), (IObservable)null!, new Subject(), new Subject(), - (a, b, c, d, e) => a + b + c + d + e); + static (a, b, c, d, e) => a + b + c + d + e); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fourth source throws . - /// + /// Verifies that a null fourth source throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource4_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), (IObservable)null!, new Subject(), - (a, b, c, d, e) => a + b + c + d + e); + static (a, b, c, d, e) => a + b + c + d + e); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fifth source throws . - /// + /// Verifies that a null fifth source throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource5_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), new Subject(), (IObservable)null!, - (a, b, c, d, e) => a + b + c + d + e); + static (a, b, c, d, e) => a + b + c + d + e); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null result selector throws . - /// + /// Verifies that a null result selector throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullResultSelector_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -160,9 +146,7 @@ public async Task Constructor_NullResultSelector_Throws() await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that subscribing with a null observer throws . - /// + /// Verifies that subscribing with a null observer throws . /// A representing the asynchronous unit test. [Test] public async Task Subscribe_NullObserver_Throws() @@ -173,16 +157,14 @@ public async Task Subscribe_NullObserver_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e) => a + b + c + d + e); + static (a, b, c, d, e) => a + b + c + d + e); var act = () => combined.Subscribe(null!); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that disposing twice does not throw an exception. - /// + /// Verifies that disposing twice does not throw an exception. /// A representing the asynchronous unit test. [Test] public async Task Dispose_CalledTwice_NoException() @@ -193,18 +175,16 @@ public async Task Dispose_CalledTwice_NoException() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e) => a + b + c + d + e); + static (a, b, c, d, e) => a + b + c + d + e); - var subscription = combined.Subscribe(new AnonymousObserver(_ => { }, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(static _ => { }, static _ => { }, static () => { })); subscription.Dispose(); subscription.Dispose(); await Assert.That(subscription.GetType()).IsNotNull(); } - /// - /// Verifies that a source emitting after dispose does not throw. - /// + /// Verifies that a source emitting after dispose does not throw. /// A representing the asynchronous unit test. [Test] public async Task SourceEmitsAfterDispose_NoException() @@ -220,10 +200,10 @@ public async Task SourceEmitsAfterDispose_NoException() source3, source4, source5, - (a, b, c, d, e) => a + b + c + d + e); + static (a, b, c, d, e) => a + b + c + d + e); var results = new List(); - var subscription = combined.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); source1.OnNext(FirstValue); source2.OnNext(SecondValue); @@ -242,9 +222,7 @@ public async Task SourceEmitsAfterDispose_NoException() await Assert.That(results[0]).IsEqualTo(ExpectedSum); } - /// - /// Verifies that an error after dispose is ignored. - /// + /// Verifies that an error after dispose is ignored. /// A representing the asynchronous unit test. [Test] public async Task ErrorAfterDispose_IsIgnored() @@ -260,13 +238,13 @@ public async Task ErrorAfterDispose_IsIgnored() source3, source4, source5, - (a, b, c, d, e) => a + b + c + d + e); + static (a, b, c, d, e) => a + b + c + d + e); Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); subscription.Dispose(); source1.OnError(new InvalidOperationException(IgnoredErrorMessage)); @@ -297,13 +275,13 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() manual3, manual4, manual5, - (a, b, c, d, e) => a + b + c + d + e); + static (a, b, c, d, e) => a + b + c + d + e); Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); // Set all has-value flags so TryEmit reaches _observer?.OnNext manual1.Observer!.OnNext(FirstValue); @@ -329,9 +307,7 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() await Assert.That(receivedError).IsNull(); } - /// - /// Verifies that an error in the first source observable is propagated to the subscriber. - /// + /// Verifies that an error in the first source observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task ErrorInSource1_PropagatedToSubscriber() @@ -347,15 +323,15 @@ public async Task ErrorInSource1_PropagatedToSubscriber() source3, source4, source5, - (a, b, c, d, e) => $"{a}-{b}-{c}-{d}-{e}"); + static (a, b, c, d, e) => $"{a}-{b}-{c}-{d}-{e}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source1 error"); source1.OnError(expectedError); @@ -365,9 +341,7 @@ public async Task ErrorInSource1_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the second source observable is propagated to the subscriber. - /// + /// Verifies that an error in the second source observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task ErrorInSource2_PropagatedToSubscriber() @@ -383,15 +357,15 @@ public async Task ErrorInSource2_PropagatedToSubscriber() source3, source4, source5, - (a, b, c, d, e) => $"{a}-{b}-{c}-{d}-{e}"); + static (a, b, c, d, e) => $"{a}-{b}-{c}-{d}-{e}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source2 error"); source2.OnError(expectedError); @@ -401,9 +375,7 @@ public async Task ErrorInSource2_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the third source observable is propagated to the subscriber. - /// + /// Verifies that an error in the third source observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task ErrorInSource3_PropagatedToSubscriber() @@ -419,15 +391,15 @@ public async Task ErrorInSource3_PropagatedToSubscriber() source3, source4, source5, - (a, b, c, d, e) => $"{a}-{b}-{c}-{d}-{e}"); + static (a, b, c, d, e) => $"{a}-{b}-{c}-{d}-{e}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source3 error"); source3.OnError(expectedError); @@ -437,9 +409,7 @@ public async Task ErrorInSource3_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fourth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fourth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task ErrorInSource4_PropagatedToSubscriber() @@ -455,15 +425,15 @@ public async Task ErrorInSource4_PropagatedToSubscriber() source3, source4, source5, - (a, b, c, d, e) => $"{a}-{b}-{c}-{d}-{e}"); + static (a, b, c, d, e) => $"{a}-{b}-{c}-{d}-{e}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source4 error"); source4.OnError(expectedError); @@ -473,9 +443,7 @@ public async Task ErrorInSource4_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fifth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fifth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task ErrorInSource5_PropagatedToSubscriber() @@ -491,15 +459,15 @@ public async Task ErrorInSource5_PropagatedToSubscriber() source3, source4, source5, - (a, b, c, d, e) => $"{a}-{b}-{c}-{d}-{e}"); + static (a, b, c, d, e) => $"{a}-{b}-{c}-{d}-{e}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source5 error"); source5.OnError(expectedError); @@ -509,9 +477,7 @@ public async Task ErrorInSource5_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that OnCompleted from a single source does not propagate completion. - /// + /// Verifies that OnCompleted from a single source does not propagate completion. /// A representing the asynchronous unit test. [Test] public async Task CompletedInSource_DoesNotPropagateCompletion() @@ -527,14 +493,14 @@ public async Task CompletedInSource_DoesNotPropagateCompletion() source3, source4, source5, - (a, b, c, d, e) => $"{a}-{b}-{c}-{d}-{e}"); + static (a, b, c, d, e) => $"{a}-{b}-{c}-{d}-{e}"); var completed = false; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, - _ => { }, + static _ => { }, () => completed = true)); source1.OnNext(FirstValue); @@ -553,15 +519,12 @@ public async Task CompletedInSource_DoesNotPropagateCompletion() await Assert.That(results).Count().IsEqualTo(ExpectedEmissionCount); } - /// - /// A simple observer implementation that delegates to provided action callbacks. - /// + /// A simple observer implementation that delegates to provided action callbacks. /// The type of elements observed. /// The action to invoke for each observed element. /// The action to invoke when an error occurs. /// The action to invoke when the sequence completes. - private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) - : IObserver + private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) : IObserver { /// public void OnCompleted() => onCompleted(); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest6ObservableTests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest6ObservableTests.cs index 04f1b69..26adcb6 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest6ObservableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest6ObservableTests.cs @@ -8,9 +8,7 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Unit tests for edge cases. -/// +/// Unit tests for edge cases. public class CombineLatest6ObservableTests { /// The value emitted by the first source on the initial round. @@ -58,122 +56,108 @@ public class CombineLatest6ObservableTests /// The message used for errors that are expected to be ignored. private const string IgnoredErrorMessage = "should be ignored"; - /// - /// Verifies that a null first source throws . - /// + /// Verifies that a null first source throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource1_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( (IObservable)null!, new Subject(), new Subject(), new Subject(), new Subject(), new Subject(), - (Func)((a, b, c, d, e, f) => a + b + c + d + e + f)); + (Func)(static (a, b, c, d, e, f) => a + b + c + d + e + f)); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null second source throws . - /// + /// Verifies that a null second source throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource2_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), (IObservable)null!, new Subject(), new Subject(), new Subject(), new Subject(), - (Func)((a, b, c, d, e, f) => a + b + c + d + e + f)); + (Func)(static (a, b, c, d, e, f) => a + b + c + d + e + f)); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null third source throws . - /// + /// Verifies that a null third source throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource3_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), (IObservable)null!, new Subject(), new Subject(), new Subject(), - (Func)((a, b, c, d, e, f) => a + b + c + d + e + f)); + (Func)(static (a, b, c, d, e, f) => a + b + c + d + e + f)); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fourth source throws . - /// + /// Verifies that a null fourth source throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource4_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), (IObservable)null!, new Subject(), new Subject(), - (Func)((a, b, c, d, e, f) => a + b + c + d + e + f)); + (Func)(static (a, b, c, d, e, f) => a + b + c + d + e + f)); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fifth source throws . - /// + /// Verifies that a null fifth source throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource5_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), new Subject(), (IObservable)null!, new Subject(), - (Func)((a, b, c, d, e, f) => a + b + c + d + e + f)); + (Func)(static (a, b, c, d, e, f) => a + b + c + d + e + f)); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null sixth source throws . - /// + /// Verifies that a null sixth source throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource6_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), new Subject(), new Subject(), (IObservable)null!, - (Func)((a, b, c, d, e, f) => a + b + c + d + e + f)); + (Func)(static (a, b, c, d, e, f) => a + b + c + d + e + f)); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null result selector throws . - /// + /// Verifies that a null result selector throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullResultSelector_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -184,9 +168,7 @@ public async Task Constructor_NullResultSelector_Throws() await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that subscribing with a null observer throws . - /// + /// Verifies that subscribing with a null observer throws . /// A representing the asynchronous unit test. [Test] public async Task Subscribe_NullObserver_Throws() @@ -198,16 +180,14 @@ public async Task Subscribe_NullObserver_Throws() new Subject(), new Subject(), new Subject(), - (Func)((a, b, c, d, e, f) => a + b + c + d + e + f)); + (Func)(static (a, b, c, d, e, f) => a + b + c + d + e + f)); var act = () => combined.Subscribe(null!); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that disposing twice does not throw an exception. - /// + /// Verifies that disposing twice does not throw an exception. /// A representing the asynchronous unit test. [Test] public async Task Dispose_CalledTwice_NoException() @@ -219,18 +199,16 @@ public async Task Dispose_CalledTwice_NoException() new Subject(), new Subject(), new Subject(), - (Func)((a, b, c, d, e, f) => a + b + c + d + e + f)); + (Func)(static (a, b, c, d, e, f) => a + b + c + d + e + f)); - var subscription = combined.Subscribe(new AnonymousObserver(_ => { }, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(static _ => { }, static _ => { }, static () => { })); subscription.Dispose(); subscription.Dispose(); await Assert.That(subscription.GetType()).IsNotNull(); } - /// - /// Verifies that a source emitting after dispose does not throw. - /// + /// Verifies that a source emitting after dispose does not throw. /// A representing the asynchronous unit test. [Test] public async Task SourceEmitsAfterDispose_NoException() @@ -248,10 +226,10 @@ public async Task SourceEmitsAfterDispose_NoException() source4, source5, source6, - (Func)((a, b, c, d, e, f) => a + b + c + d + e + f)); + (Func)(static (a, b, c, d, e, f) => a + b + c + d + e + f)); var results = new List(); - var subscription = combined.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); source1.OnNext(FirstValue); source2.OnNext(SecondValue); @@ -268,9 +246,7 @@ public async Task SourceEmitsAfterDispose_NoException() await Assert.That(results[0]).IsEqualTo(ExpectedSum); } - /// - /// Verifies that an error after dispose is ignored. - /// + /// Verifies that an error after dispose is ignored. /// A representing the asynchronous unit test. [Test] public async Task ErrorAfterDispose_IsIgnored() @@ -288,13 +264,13 @@ public async Task ErrorAfterDispose_IsIgnored() source4, source5, source6, - (Func)((a, b, c, d, e, f) => a + b + c + d + e + f)); + (Func)(static (a, b, c, d, e, f) => a + b + c + d + e + f)); Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); subscription.Dispose(); source1.OnError(new InvalidOperationException(IgnoredErrorMessage)); @@ -328,13 +304,13 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() manual4, manual5, manual6, - (Func)((a, b, c, d, e, f) => a + b + c + d + e + f)); + (Func)(static (a, b, c, d, e, f) => a + b + c + d + e + f)); Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); // Set all has-value flags so TryEmit reaches _observer?.OnNext manual1.Observer!.OnNext(FirstValue); @@ -363,9 +339,7 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() await Assert.That(receivedError).IsNull(); } - /// - /// Verifies that an error in the first source observable is propagated to the subscriber. - /// + /// Verifies that an error in the first source observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task ErrorInSource1_PropagatedToSubscriber() @@ -383,15 +357,15 @@ public async Task ErrorInSource1_PropagatedToSubscriber() source4, source5, source6, - (a, b, c, d, e, f) => $"{a}-{b}-{c}-{d}-{e}-{f}"); + static (a, b, c, d, e, f) => $"{a}-{b}-{c}-{d}-{e}-{f}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source1 error"); source1.OnError(expectedError); @@ -401,9 +375,7 @@ public async Task ErrorInSource1_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the second source observable is propagated to the subscriber. - /// + /// Verifies that an error in the second source observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task ErrorInSource2_PropagatedToSubscriber() @@ -421,15 +393,15 @@ public async Task ErrorInSource2_PropagatedToSubscriber() source4, source5, source6, - (a, b, c, d, e, f) => $"{a}-{b}-{c}-{d}-{e}-{f}"); + static (a, b, c, d, e, f) => $"{a}-{b}-{c}-{d}-{e}-{f}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source2 error"); source2.OnError(expectedError); @@ -439,9 +411,7 @@ public async Task ErrorInSource2_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the third source observable is propagated to the subscriber. - /// + /// Verifies that an error in the third source observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task ErrorInSource3_PropagatedToSubscriber() @@ -459,15 +429,15 @@ public async Task ErrorInSource3_PropagatedToSubscriber() source4, source5, source6, - (a, b, c, d, e, f) => $"{a}-{b}-{c}-{d}-{e}-{f}"); + static (a, b, c, d, e, f) => $"{a}-{b}-{c}-{d}-{e}-{f}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source3 error"); source3.OnError(expectedError); @@ -477,9 +447,7 @@ public async Task ErrorInSource3_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fourth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fourth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task ErrorInSource4_PropagatedToSubscriber() @@ -497,15 +465,15 @@ public async Task ErrorInSource4_PropagatedToSubscriber() source4, source5, source6, - (a, b, c, d, e, f) => $"{a}-{b}-{c}-{d}-{e}-{f}"); + static (a, b, c, d, e, f) => $"{a}-{b}-{c}-{d}-{e}-{f}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source4 error"); source4.OnError(expectedError); @@ -515,9 +483,7 @@ public async Task ErrorInSource4_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fifth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fifth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task ErrorInSource5_PropagatedToSubscriber() @@ -535,15 +501,15 @@ public async Task ErrorInSource5_PropagatedToSubscriber() source4, source5, source6, - (a, b, c, d, e, f) => $"{a}-{b}-{c}-{d}-{e}-{f}"); + static (a, b, c, d, e, f) => $"{a}-{b}-{c}-{d}-{e}-{f}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source5 error"); source5.OnError(expectedError); @@ -553,9 +519,7 @@ public async Task ErrorInSource5_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the sixth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the sixth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task ErrorInSource6_PropagatedToSubscriber() @@ -573,15 +537,15 @@ public async Task ErrorInSource6_PropagatedToSubscriber() source4, source5, source6, - (a, b, c, d, e, f) => $"{a}-{b}-{c}-{d}-{e}-{f}"); + static (a, b, c, d, e, f) => $"{a}-{b}-{c}-{d}-{e}-{f}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source6 error"); source6.OnError(expectedError); @@ -591,9 +555,7 @@ public async Task ErrorInSource6_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that OnCompleted from a single source does not propagate completion. - /// + /// Verifies that OnCompleted from a single source does not propagate completion. /// A representing the asynchronous unit test. [Test] public async Task CompletedInSource_DoesNotPropagateCompletion() @@ -611,14 +573,14 @@ public async Task CompletedInSource_DoesNotPropagateCompletion() source4, source5, source6, - (a, b, c, d, e, f) => $"{a}-{b}-{c}-{d}-{e}-{f}"); + static (a, b, c, d, e, f) => $"{a}-{b}-{c}-{d}-{e}-{f}"); var completed = false; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, - _ => { }, + static _ => { }, () => completed = true)); source1.OnNext(FirstValue); @@ -639,15 +601,12 @@ public async Task CompletedInSource_DoesNotPropagateCompletion() await Assert.That(results).Count().IsEqualTo(ExpectedEmissionCount); } - /// - /// A simple observer implementation that delegates to provided action callbacks. - /// + /// A simple observer implementation that delegates to provided action callbacks. /// The type of elements observed. /// The action to invoke for each observed element. /// The action to invoke when an error occurs. /// The action to invoke when the sequence completes. - private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) - : IObserver + private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) : IObserver { /// public void OnCompleted() => onCompleted(); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest7ObservableTests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest7ObservableTests.cs index 088f57b..2a49c58 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest7ObservableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest7ObservableTests.cs @@ -8,9 +8,7 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Unit tests for edge cases. -/// +/// Unit tests for edge cases. public class CombineLatest7ObservableTests { /// The value emitted by the first source on the initial round. @@ -64,14 +62,12 @@ public class CombineLatest7ObservableTests /// The message used for errors that are expected to be ignored. private const string IgnoredErrorMessage = "should be ignored"; - /// - /// Verifies that a null first source throws . - /// + /// Verifies that a null first source throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource1_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( (IObservable)null!, new Subject(), new Subject(), @@ -79,18 +75,16 @@ public async Task Constructor_NullSource1_Throws() new Subject(), new Subject(), new Subject(), - (Func)((a, b, c, d, e, f, g) => a + b + c + d + e + f + g)); + (Func)(static (a, b, c, d, e, f, g) => a + b + c + d + e + f + g)); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null second source throws . - /// + /// Verifies that a null second source throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource2_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), (IObservable)null!, new Subject(), @@ -98,18 +92,16 @@ public async Task Constructor_NullSource2_Throws() new Subject(), new Subject(), new Subject(), - (Func)((a, b, c, d, e, f, g) => a + b + c + d + e + f + g)); + (Func)(static (a, b, c, d, e, f, g) => a + b + c + d + e + f + g)); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null third source throws . - /// + /// Verifies that a null third source throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource3_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), (IObservable)null!, @@ -117,18 +109,16 @@ public async Task Constructor_NullSource3_Throws() new Subject(), new Subject(), new Subject(), - (Func)((a, b, c, d, e, f, g) => a + b + c + d + e + f + g)); + (Func)(static (a, b, c, d, e, f, g) => a + b + c + d + e + f + g)); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fourth source throws . - /// + /// Verifies that a null fourth source throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource4_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -136,18 +126,16 @@ public async Task Constructor_NullSource4_Throws() new Subject(), new Subject(), new Subject(), - (Func)((a, b, c, d, e, f, g) => a + b + c + d + e + f + g)); + (Func)(static (a, b, c, d, e, f, g) => a + b + c + d + e + f + g)); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fifth source throws . - /// + /// Verifies that a null fifth source throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource5_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -155,13 +143,11 @@ public async Task Constructor_NullSource5_Throws() (IObservable)null!, new Subject(), new Subject(), - (Func)((a, b, c, d, e, f, g) => a + b + c + d + e + f + g)); + (Func)(static (a, b, c, d, e, f, g) => a + b + c + d + e + f + g)); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null sixth source throws . - /// + /// Verifies that a null sixth source throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource6_Throws() @@ -175,19 +161,17 @@ static IObservable Act() => new Subject(), (IObservable)null!, new Subject(), - (Func)((a, b, c, d, e, f, g) => a + b + c + d + e + f + g)); + (Func)(static (a, b, c, d, e, f, g) => a + b + c + d + e + f + g)); await Assert.That(Act).ThrowsExactly(); } - /// - /// Verifies that a null seventh source throws . - /// + /// Verifies that a null seventh source throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource7_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -195,18 +179,16 @@ public async Task Constructor_NullSource7_Throws() new Subject(), new Subject(), (IObservable)null!, - (Func)((a, b, c, d, e, f, g) => a + b + c + d + e + f + g)); + (Func)(static (a, b, c, d, e, f, g) => a + b + c + d + e + f + g)); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null result selector throws . - /// + /// Verifies that a null result selector throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullResultSelector_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -218,9 +200,7 @@ public async Task Constructor_NullResultSelector_Throws() await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that subscribing with a null observer throws . - /// + /// Verifies that subscribing with a null observer throws . /// A representing the asynchronous unit test. [Test] public async Task Subscribe_NullObserver_Throws() @@ -233,16 +213,14 @@ public async Task Subscribe_NullObserver_Throws() new Subject(), new Subject(), new Subject(), - (Func)((a, b, c, d, e, f, g) => a + b + c + d + e + f + g)); + (Func)(static (a, b, c, d, e, f, g) => a + b + c + d + e + f + g)); var act = () => combined.Subscribe(null!); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that disposing twice does not throw an exception. - /// + /// Verifies that disposing twice does not throw an exception. /// A representing the asynchronous unit test. [Test] public async Task Dispose_CalledTwice_NoException() @@ -255,18 +233,16 @@ public async Task Dispose_CalledTwice_NoException() new Subject(), new Subject(), new Subject(), - (Func)((a, b, c, d, e, f, g) => a + b + c + d + e + f + g)); + (Func)(static (a, b, c, d, e, f, g) => a + b + c + d + e + f + g)); - var subscription = combined.Subscribe(new AnonymousObserver(_ => { }, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(static _ => { }, static _ => { }, static () => { })); subscription.Dispose(); subscription.Dispose(); await Assert.That(subscription.GetType()).IsNotNull(); } - /// - /// Verifies that a source emitting after dispose does not throw. - /// + /// Verifies that a source emitting after dispose does not throw. /// A representing the asynchronous unit test. [Test] public async Task SourceEmitsAfterDispose_NoException() @@ -286,10 +262,10 @@ public async Task SourceEmitsAfterDispose_NoException() source5, source6, source7, - (Func)((a, b, c, d, e, f, g) => a + b + c + d + e + f + g)); + (Func)(static (a, b, c, d, e, f, g) => a + b + c + d + e + f + g)); var results = new List(); - var subscription = combined.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); source1.OnNext(FirstValue); source2.OnNext(SecondValue); @@ -307,9 +283,7 @@ public async Task SourceEmitsAfterDispose_NoException() await Assert.That(results[0]).IsEqualTo(ExpectedSum); } - /// - /// Verifies that an error after dispose is ignored. - /// + /// Verifies that an error after dispose is ignored. /// A representing the asynchronous unit test. [Test] public async Task ErrorAfterDispose_IsIgnored() @@ -329,13 +303,13 @@ public async Task ErrorAfterDispose_IsIgnored() source5, source6, source7, - (Func)((a, b, c, d, e, f, g) => a + b + c + d + e + f + g)); + (Func)(static (a, b, c, d, e, f, g) => a + b + c + d + e + f + g)); Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); subscription.Dispose(); source1.OnError(new InvalidOperationException(IgnoredErrorMessage)); @@ -372,13 +346,13 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() manual5, manual6, manual7, - (Func)((a, b, c, d, e, f, g) => a + b + c + d + e + f + g)); + (Func)(static (a, b, c, d, e, f, g) => a + b + c + d + e + f + g)); Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); // Set all has-value flags so TryEmit reaches _observer?.OnNext manual1.Observer!.OnNext(FirstValue); @@ -410,9 +384,7 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() await Assert.That(receivedError).IsNull(); } - /// - /// Verifies that an error in the first source observable is propagated to the subscriber. - /// + /// Verifies that an error in the first source observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task ErrorInSource1_PropagatedToSubscriber() @@ -432,15 +404,15 @@ public async Task ErrorInSource1_PropagatedToSubscriber() source5, source6, source7, - (a, b, c, d, e, f, g) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}"); + static (a, b, c, d, e, f, g) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source1 error"); source1.OnError(expectedError); @@ -450,9 +422,7 @@ public async Task ErrorInSource1_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the second source observable is propagated to the subscriber. - /// + /// Verifies that an error in the second source observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task ErrorInSource2_PropagatedToSubscriber() @@ -472,15 +442,15 @@ public async Task ErrorInSource2_PropagatedToSubscriber() source5, source6, source7, - (a, b, c, d, e, f, g) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}"); + static (a, b, c, d, e, f, g) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source2 error"); source2.OnError(expectedError); @@ -490,9 +460,7 @@ public async Task ErrorInSource2_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the third source observable is propagated to the subscriber. - /// + /// Verifies that an error in the third source observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task ErrorInSource3_PropagatedToSubscriber() @@ -512,15 +480,15 @@ public async Task ErrorInSource3_PropagatedToSubscriber() source5, source6, source7, - (a, b, c, d, e, f, g) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}"); + static (a, b, c, d, e, f, g) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source3 error"); source3.OnError(expectedError); @@ -530,9 +498,7 @@ public async Task ErrorInSource3_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fourth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fourth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task ErrorInSource4_PropagatedToSubscriber() @@ -552,15 +518,15 @@ public async Task ErrorInSource4_PropagatedToSubscriber() source5, source6, source7, - (a, b, c, d, e, f, g) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}"); + static (a, b, c, d, e, f, g) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source4 error"); source4.OnError(expectedError); @@ -570,9 +536,7 @@ public async Task ErrorInSource4_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fifth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fifth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task ErrorInSource5_PropagatedToSubscriber() @@ -592,15 +556,15 @@ public async Task ErrorInSource5_PropagatedToSubscriber() source5, source6, source7, - (a, b, c, d, e, f, g) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}"); + static (a, b, c, d, e, f, g) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source5 error"); source5.OnError(expectedError); @@ -610,9 +574,7 @@ public async Task ErrorInSource5_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the sixth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the sixth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task ErrorInSource6_PropagatedToSubscriber() @@ -632,15 +594,15 @@ public async Task ErrorInSource6_PropagatedToSubscriber() source5, source6, source7, - (a, b, c, d, e, f, g) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}"); + static (a, b, c, d, e, f, g) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source6 error"); source6.OnError(expectedError); @@ -650,9 +612,7 @@ public async Task ErrorInSource6_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the seventh source observable is propagated to the subscriber. - /// + /// Verifies that an error in the seventh source observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task ErrorInSource7_PropagatedToSubscriber() @@ -672,15 +632,15 @@ public async Task ErrorInSource7_PropagatedToSubscriber() source5, source6, source7, - (a, b, c, d, e, f, g) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}"); + static (a, b, c, d, e, f, g) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source7 error"); source7.OnError(expectedError); @@ -690,9 +650,7 @@ public async Task ErrorInSource7_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that OnCompleted from a single source does not propagate completion. - /// + /// Verifies that OnCompleted from a single source does not propagate completion. /// A representing the asynchronous unit test. [Test] public async Task CompletedInSource_DoesNotPropagateCompletion() @@ -712,14 +670,14 @@ public async Task CompletedInSource_DoesNotPropagateCompletion() source5, source6, source7, - (a, b, c, d, e, f, g) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}"); + static (a, b, c, d, e, f, g) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}"); var completed = false; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, - _ => { }, + static _ => { }, () => completed = true)); source1.OnNext(FirstValue); @@ -742,15 +700,12 @@ public async Task CompletedInSource_DoesNotPropagateCompletion() await Assert.That(results).Count().IsEqualTo(ExpectedEmissionCount); } - /// - /// A simple observer implementation that delegates to provided action callbacks. - /// + /// A simple observer implementation that delegates to provided action callbacks. /// The type of elements observed. /// The action to invoke for each observed element. /// The action to invoke when an error occurs. /// The action to invoke when the sequence completes. - private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) - : IObserver + private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) : IObserver { /// public void OnCompleted() => onCompleted(); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest8ObservableTests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest8ObservableTests.cs index d0b9642..4857483 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest8ObservableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest8ObservableTests.cs @@ -8,9 +8,7 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Unit tests for edge cases. -/// +/// Unit tests for edge cases. public class CombineLatest8ObservableTests { /// The value emitted by the first source on the initial round. @@ -70,19 +68,13 @@ public class CombineLatest8ObservableTests /// The message used for errors that are expected to be ignored. private const string IgnoredErrorMessage = "should be ignored"; - /// - /// Verifies that a null first source throws . - /// + /// Verifies that a null first source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource1_Throws() { Func selector = - (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h; + static (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h; var act = () => CombineLatestObservable.Create( (IObservable)null!, new Subject(), @@ -96,19 +88,13 @@ public async Task Constructor_NullSource1_Throws() await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null second source throws . - /// + /// Verifies that a null second source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource2_Throws() { Func selector = - (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h; + static (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h; var act = () => CombineLatestObservable.Create( new Subject(), (IObservable)null!, @@ -122,19 +108,13 @@ public async Task Constructor_NullSource2_Throws() await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null third source throws . - /// + /// Verifies that a null third source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource3_Throws() { Func selector = - (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h; + static (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h; var act = () => CombineLatestObservable.Create( new Subject(), new Subject(), @@ -148,19 +128,13 @@ public async Task Constructor_NullSource3_Throws() await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fourth source throws . - /// + /// Verifies that a null fourth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource4_Throws() { Func selector = - (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h; + static (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h; var act = () => CombineLatestObservable.Create( new Subject(), new Subject(), @@ -174,19 +148,13 @@ public async Task Constructor_NullSource4_Throws() await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fifth source throws . - /// + /// Verifies that a null fifth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource5_Throws() { Func selector = - (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h; + static (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h; var act = () => CombineLatestObservable.Create( new Subject(), new Subject(), @@ -200,19 +168,13 @@ public async Task Constructor_NullSource5_Throws() await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null sixth source throws . - /// + /// Verifies that a null sixth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource6_Throws() { Func selector = - (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h; + static (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h; var act = () => CombineLatestObservable.Create( new Subject(), new Subject(), @@ -226,19 +188,13 @@ public async Task Constructor_NullSource6_Throws() await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null seventh source throws . - /// + /// Verifies that a null seventh source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource7_Throws() { Func selector = - (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h; + static (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h; var act = () => CombineLatestObservable.Create( new Subject(), new Subject(), @@ -252,19 +208,13 @@ public async Task Constructor_NullSource7_Throws() await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null eighth source throws . - /// + /// Verifies that a null eighth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource8_Throws() { Func selector = - (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h; + static (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h; var act = () => CombineLatestObservable.Create( new Subject(), new Subject(), @@ -278,14 +228,12 @@ public async Task Constructor_NullSource8_Throws() await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null result selector throws . - /// + /// Verifies that a null result selector throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullResultSelector_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -298,19 +246,13 @@ public async Task Constructor_NullResultSelector_Throws() await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that subscribing with a null observer throws . - /// + /// Verifies that subscribing with a null observer throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Subscribe_NullObserver_Throws() { Func selector = - (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h; + static (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h; var combined = CombineLatestObservable.Create( new Subject(), new Subject(), @@ -327,19 +269,13 @@ public async Task Subscribe_NullObserver_Throws() await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that disposing twice does not throw an exception. - /// + /// Verifies that disposing twice does not throw an exception. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Dispose_CalledTwice_NoException() { Func selector = - (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h; + static (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h; var combined = CombineLatestObservable.Create( new Subject(), new Subject(), @@ -351,21 +287,15 @@ public async Task Dispose_CalledTwice_NoException() new Subject(), selector); - var subscription = combined.Subscribe(new AnonymousObserver(_ => { }, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(static _ => { }, static _ => { }, static () => { })); subscription.Dispose(); subscription.Dispose(); await Assert.That(subscription.GetType()).IsNotNull(); } - /// - /// Verifies that a source emitting after dispose does not throw. - /// + /// Verifies that a source emitting after dispose does not throw. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task SourceEmitsAfterDispose_NoException() { @@ -378,7 +308,7 @@ public async Task SourceEmitsAfterDispose_NoException() var source7 = new Subject(); var source8 = new Subject(); Func selector = - (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h; + static (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h; var combined = CombineLatestObservable.Create( source1, source2, @@ -391,7 +321,7 @@ public async Task SourceEmitsAfterDispose_NoException() selector); var results = new List(); - var subscription = combined.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); source1.OnNext(FirstValue); source2.OnNext(SecondValue); @@ -410,14 +340,8 @@ public async Task SourceEmitsAfterDispose_NoException() await Assert.That(results[0]).IsEqualTo(ExpectedSum); } - /// - /// Verifies that an error after dispose is ignored. - /// + /// Verifies that an error after dispose is ignored. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorAfterDispose_IsIgnored() { @@ -430,7 +354,7 @@ public async Task ErrorAfterDispose_IsIgnored() var source7 = new Subject(); var source8 = new Subject(); Func selector = - (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h; + static (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h; var combined = CombineLatestObservable.Create( source1, source2, @@ -444,9 +368,9 @@ public async Task ErrorAfterDispose_IsIgnored() Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); subscription.Dispose(); source1.OnError(new InvalidOperationException(IgnoredErrorMessage)); @@ -466,10 +390,6 @@ public async Task ErrorAfterDispose_IsIgnored() /// when the subscription has been disposed but the observers are still reachable. /// /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorAfterDispose_AllObservers_CoverNullPath() { @@ -482,7 +402,7 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() var manual7 = new ManualObservable(); var manual8 = new ManualObservable(); Func selector = - (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h; + static (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h; var combined = CombineLatestObservable.Create( manual1, manual2, @@ -496,9 +416,9 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); // Set all has-value flags so TryEmit reaches _observer?.OnNext manual1.Observer!.OnNext(FirstValue); @@ -533,14 +453,8 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() await Assert.That(receivedError).IsNull(); } - /// - /// Verifies that an error in the first source observable is propagated to the subscriber. - /// + /// Verifies that an error in the first source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource1_PropagatedToSubscriber() { @@ -561,15 +475,15 @@ public async Task ErrorInSource1_PropagatedToSubscriber() source6, source7, source8, - (a, b, c, d, e, f, g, h) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}"); + static (a, b, c, d, e, f, g, h) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source1 error"); source1.OnError(expectedError); @@ -579,14 +493,8 @@ public async Task ErrorInSource1_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the second source observable is propagated to the subscriber. - /// + /// Verifies that an error in the second source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource2_PropagatedToSubscriber() { @@ -607,15 +515,15 @@ public async Task ErrorInSource2_PropagatedToSubscriber() source6, source7, source8, - (a, b, c, d, e, f, g, h) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}"); + static (a, b, c, d, e, f, g, h) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source2 error"); source2.OnError(expectedError); @@ -625,14 +533,8 @@ public async Task ErrorInSource2_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the third source observable is propagated to the subscriber. - /// + /// Verifies that an error in the third source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource3_PropagatedToSubscriber() { @@ -653,15 +555,15 @@ public async Task ErrorInSource3_PropagatedToSubscriber() source6, source7, source8, - (a, b, c, d, e, f, g, h) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}"); + static (a, b, c, d, e, f, g, h) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source3 error"); source3.OnError(expectedError); @@ -671,14 +573,8 @@ public async Task ErrorInSource3_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fourth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fourth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource4_PropagatedToSubscriber() { @@ -699,15 +595,15 @@ public async Task ErrorInSource4_PropagatedToSubscriber() source6, source7, source8, - (a, b, c, d, e, f, g, h) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}"); + static (a, b, c, d, e, f, g, h) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source4 error"); source4.OnError(expectedError); @@ -717,14 +613,8 @@ public async Task ErrorInSource4_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fifth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fifth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource5_PropagatedToSubscriber() { @@ -745,15 +635,15 @@ public async Task ErrorInSource5_PropagatedToSubscriber() source6, source7, source8, - (a, b, c, d, e, f, g, h) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}"); + static (a, b, c, d, e, f, g, h) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source5 error"); source5.OnError(expectedError); @@ -763,14 +653,8 @@ public async Task ErrorInSource5_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the sixth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the sixth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource6_PropagatedToSubscriber() { @@ -791,15 +675,15 @@ public async Task ErrorInSource6_PropagatedToSubscriber() source6, source7, source8, - (a, b, c, d, e, f, g, h) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}"); + static (a, b, c, d, e, f, g, h) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source6 error"); source6.OnError(expectedError); @@ -809,14 +693,8 @@ public async Task ErrorInSource6_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the seventh source observable is propagated to the subscriber. - /// + /// Verifies that an error in the seventh source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource7_PropagatedToSubscriber() { @@ -837,15 +715,15 @@ public async Task ErrorInSource7_PropagatedToSubscriber() source6, source7, source8, - (a, b, c, d, e, f, g, h) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}"); + static (a, b, c, d, e, f, g, h) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source7 error"); source7.OnError(expectedError); @@ -855,14 +733,8 @@ public async Task ErrorInSource7_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the eighth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the eighth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource8_PropagatedToSubscriber() { @@ -883,15 +755,15 @@ public async Task ErrorInSource8_PropagatedToSubscriber() source6, source7, source8, - (a, b, c, d, e, f, g, h) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}"); + static (a, b, c, d, e, f, g, h) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source8 error"); source8.OnError(expectedError); @@ -901,14 +773,8 @@ public async Task ErrorInSource8_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that OnCompleted from a single source does not propagate completion. - /// + /// Verifies that OnCompleted from a single source does not propagate completion. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task CompletedInSource_DoesNotPropagateCompletion() { @@ -929,14 +795,14 @@ public async Task CompletedInSource_DoesNotPropagateCompletion() source6, source7, source8, - (a, b, c, d, e, f, g, h) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}"); + static (a, b, c, d, e, f, g, h) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}"); var completed = false; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, - _ => { }, + static _ => { }, () => completed = true)); source1.OnNext(FirstValue); @@ -961,15 +827,12 @@ public async Task CompletedInSource_DoesNotPropagateCompletion() await Assert.That(results).Count().IsEqualTo(ExpectedEmissionCount); } - /// - /// A simple observer implementation that delegates to provided action callbacks. - /// + /// A simple observer implementation that delegates to provided action callbacks. /// The type of elements observed. /// The action to invoke for each observed element. /// The action to invoke when an error occurs. /// The action to invoke when the sequence completes. - private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) - : IObserver + private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) : IObserver { /// public void OnCompleted() => onCompleted(); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest9ObservableTests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest9ObservableTests.cs index 07e1f6e..e0952e0 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest9ObservableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CombineLatest9ObservableTests.cs @@ -8,113 +8,69 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Unit tests for edge cases. -/// +/// Unit tests for edge cases. public class CombineLatest9ObservableTests { - /// - /// The exception message used for errors that the subscription is expected to ignore. - /// + /// The exception message used for errors that the subscription is expected to ignore. private const string IgnoredErrorMessage = "should be ignored"; - /// - /// The distinct sample value emitted from the second source during a combination sequence. - /// + /// The distinct sample value emitted from the second source during a combination sequence. private const int Source2Value = 2; - /// - /// The distinct sample value emitted from the third source during a combination sequence. - /// + /// The distinct sample value emitted from the third source during a combination sequence. private const int Source3Value = 3; - /// - /// The distinct sample value emitted from the fourth source during a combination sequence. - /// + /// The distinct sample value emitted from the fourth source during a combination sequence. private const int Source4Value = 4; - /// - /// The distinct sample value emitted from the fifth source during a combination sequence. - /// + /// The distinct sample value emitted from the fifth source during a combination sequence. private const int Source5Value = 5; - /// - /// The distinct sample value emitted from the sixth source during a combination sequence. - /// + /// The distinct sample value emitted from the sixth source during a combination sequence. private const int Source6Value = 6; - /// - /// The distinct sample value emitted from the seventh source during a combination sequence. - /// + /// The distinct sample value emitted from the seventh source during a combination sequence. private const int Source7Value = 7; - /// - /// The distinct sample value emitted from the eighth source during a combination sequence. - /// + /// The distinct sample value emitted from the eighth source during a combination sequence. private const int Source8Value = 8; - /// - /// The distinct sample value emitted from the ninth source during a combination sequence. - /// + /// The distinct sample value emitted from the ninth source during a combination sequence. private const int Source9Value = 9; - /// - /// The value emitted from the first source after the subscription has been disposed. - /// + /// The value emitted from the first source after the subscription has been disposed. private const int Source1ValueAfterDispose = 10; - /// - /// The value emitted from the second source after the subscription has been disposed. - /// + /// The value emitted from the second source after the subscription has been disposed. private const int Source2ValueAfterDispose = 20; - /// - /// The value emitted from the third source after the subscription has been disposed. - /// + /// The value emitted from the third source after the subscription has been disposed. private const int Source3ValueAfterDispose = 30; - /// - /// The value emitted from the fourth source after the subscription has been disposed. - /// + /// The value emitted from the fourth source after the subscription has been disposed. private const int Source4ValueAfterDispose = 40; - /// - /// The value emitted from the fifth source after the subscription has been disposed. - /// + /// The value emitted from the fifth source after the subscription has been disposed. private const int Source5ValueAfterDispose = 50; - /// - /// The value emitted from the sixth source after the subscription has been disposed. - /// + /// The value emitted from the sixth source after the subscription has been disposed. private const int Source6ValueAfterDispose = 60; - /// - /// The value emitted from the seventh source after the subscription has been disposed. - /// + /// The value emitted from the seventh source after the subscription has been disposed. private const int Source7ValueAfterDispose = 70; - /// - /// The value emitted from the eighth source after the subscription has been disposed. - /// + /// The value emitted from the eighth source after the subscription has been disposed. private const int Source8ValueAfterDispose = 80; - /// - /// The value emitted from the ninth source after the subscription has been disposed. - /// + /// The value emitted from the ninth source after the subscription has been disposed. private const int Source9ValueAfterDispose = 90; - /// - /// Verifies that a null first source throws . - /// + /// Verifies that a null first source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource1_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( (IObservable)null!, new Subject(), new Subject(), @@ -124,23 +80,17 @@ public async Task Constructor_NullSource1_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i); + static (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null second source throws . - /// + /// Verifies that a null second source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource2_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), (IObservable)null!, new Subject(), @@ -150,23 +100,17 @@ public async Task Constructor_NullSource2_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i); + static (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null third source throws . - /// + /// Verifies that a null third source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource3_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), (IObservable)null!, @@ -176,23 +120,17 @@ public async Task Constructor_NullSource3_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i); + static (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fourth source throws . - /// + /// Verifies that a null fourth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource4_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -202,23 +140,17 @@ public async Task Constructor_NullSource4_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i); + static (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null fifth source throws . - /// + /// Verifies that a null fifth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource5_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -228,23 +160,17 @@ public async Task Constructor_NullSource5_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i); + static (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null sixth source throws . - /// + /// Verifies that a null sixth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource6_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -254,23 +180,17 @@ public async Task Constructor_NullSource6_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i); + static (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null seventh source throws . - /// + /// Verifies that a null seventh source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource7_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -280,23 +200,17 @@ public async Task Constructor_NullSource7_Throws() (IObservable)null!, new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i); + static (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null eighth source throws . - /// + /// Verifies that a null eighth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource8_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -306,23 +220,17 @@ public async Task Constructor_NullSource8_Throws() new Subject(), (IObservable)null!, new Subject(), - (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i); + static (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null ninth source throws . - /// + /// Verifies that a null ninth source throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Constructor_NullSource9_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -332,19 +240,17 @@ public async Task Constructor_NullSource9_Throws() new Subject(), new Subject(), (IObservable)null!, - (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i); + static (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that a null result selector throws . - /// + /// Verifies that a null result selector throws . /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullResultSelector_Throws() { - var act = () => CombineLatestObservable.Create( + var act = static () => CombineLatestObservable.Create( new Subject(), new Subject(), new Subject(), @@ -359,14 +265,8 @@ public async Task Constructor_NullResultSelector_Throws() await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that subscribing with a null observer throws . - /// + /// Verifies that subscribing with a null observer throws . /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Subscribe_NullObserver_Throws() { @@ -380,21 +280,15 @@ public async Task Subscribe_NullObserver_Throws() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i); + static (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i); var act = () => combined.Subscribe(null!); await Assert.That(act).ThrowsExactly(); } - /// - /// Verifies that disposing twice does not throw an exception. - /// + /// Verifies that disposing twice does not throw an exception. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task Dispose_CalledTwice_NoException() { @@ -408,23 +302,17 @@ public async Task Dispose_CalledTwice_NoException() new Subject(), new Subject(), new Subject(), - (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i); + static (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i); - var subscription = combined.Subscribe(new AnonymousObserver(_ => { }, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(static _ => { }, static _ => { }, static () => { })); subscription.Dispose(); subscription.Dispose(); await Assert.That(subscription.GetType()).IsNotNull(); } - /// - /// Verifies that a source emitting after dispose does not throw. - /// + /// Verifies that a source emitting after dispose does not throw. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task SourceEmitsAfterDispose_NoException() { @@ -447,10 +335,10 @@ public async Task SourceEmitsAfterDispose_NoException() source7, source8, source9, - (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i); + static (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i); var results = new List(); - var subscription = combined.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + var subscription = combined.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); source1.OnNext(1); source2.OnNext(1); @@ -468,14 +356,8 @@ public async Task SourceEmitsAfterDispose_NoException() await Assert.That(results).Count().IsEqualTo(1); } - /// - /// Verifies that an error after dispose is ignored. - /// + /// Verifies that an error after dispose is ignored. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorAfterDispose_IsIgnored() { @@ -498,13 +380,13 @@ public async Task ErrorAfterDispose_IsIgnored() source7, source8, source9, - (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i); + static (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i); Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); subscription.Dispose(); source1.OnError(new InvalidOperationException(IgnoredErrorMessage)); @@ -525,10 +407,6 @@ public async Task ErrorAfterDispose_IsIgnored() /// when the subscription has been disposed but the observers are still reachable. /// /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorAfterDispose_AllObservers_CoverNullPath() { @@ -551,13 +429,13 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() manual7, manual8, manual9, - (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i); + static (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i); Exception? receivedError = null; var subscription = combined.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); // Set all has-value flags so TryEmit reaches _observer?.OnNext manual1.Observer!.OnNext(1); @@ -595,14 +473,8 @@ public async Task ErrorAfterDispose_AllObservers_CoverNullPath() await Assert.That(receivedError).IsNull(); } - /// - /// Verifies that an error in the first source observable is propagated to the subscriber. - /// + /// Verifies that an error in the first source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource1_PropagatedToSubscriber() { @@ -625,15 +497,15 @@ public async Task ErrorInSource1_PropagatedToSubscriber() source7, source8, source9, - (a, b, c, d, e, f, g, h, i) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}"); + static (a, b, c, d, e, f, g, h, i) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source1 error"); source1.OnError(expectedError); @@ -643,14 +515,8 @@ public async Task ErrorInSource1_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the second source observable is propagated to the subscriber. - /// + /// Verifies that an error in the second source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource2_PropagatedToSubscriber() { @@ -673,15 +539,15 @@ public async Task ErrorInSource2_PropagatedToSubscriber() source7, source8, source9, - (a, b, c, d, e, f, g, h, i) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}"); + static (a, b, c, d, e, f, g, h, i) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source2 error"); source2.OnError(expectedError); @@ -691,14 +557,8 @@ public async Task ErrorInSource2_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the third source observable is propagated to the subscriber. - /// + /// Verifies that an error in the third source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource3_PropagatedToSubscriber() { @@ -721,15 +581,15 @@ public async Task ErrorInSource3_PropagatedToSubscriber() source7, source8, source9, - (a, b, c, d, e, f, g, h, i) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}"); + static (a, b, c, d, e, f, g, h, i) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source3 error"); source3.OnError(expectedError); @@ -739,14 +599,8 @@ public async Task ErrorInSource3_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fourth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fourth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource4_PropagatedToSubscriber() { @@ -769,15 +623,15 @@ public async Task ErrorInSource4_PropagatedToSubscriber() source7, source8, source9, - (a, b, c, d, e, f, g, h, i) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}"); + static (a, b, c, d, e, f, g, h, i) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source4 error"); source4.OnError(expectedError); @@ -787,14 +641,8 @@ public async Task ErrorInSource4_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the fifth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the fifth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource5_PropagatedToSubscriber() { @@ -817,15 +665,15 @@ public async Task ErrorInSource5_PropagatedToSubscriber() source7, source8, source9, - (a, b, c, d, e, f, g, h, i) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}"); + static (a, b, c, d, e, f, g, h, i) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source5 error"); source5.OnError(expectedError); @@ -835,14 +683,8 @@ public async Task ErrorInSource5_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the sixth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the sixth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource6_PropagatedToSubscriber() { @@ -865,15 +707,15 @@ public async Task ErrorInSource6_PropagatedToSubscriber() source7, source8, source9, - (a, b, c, d, e, f, g, h, i) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}"); + static (a, b, c, d, e, f, g, h, i) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source6 error"); source6.OnError(expectedError); @@ -883,14 +725,8 @@ public async Task ErrorInSource6_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the seventh source observable is propagated to the subscriber. - /// + /// Verifies that an error in the seventh source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource7_PropagatedToSubscriber() { @@ -913,15 +749,15 @@ public async Task ErrorInSource7_PropagatedToSubscriber() source7, source8, source9, - (a, b, c, d, e, f, g, h, i) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}"); + static (a, b, c, d, e, f, g, h, i) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source7 error"); source7.OnError(expectedError); @@ -931,14 +767,8 @@ public async Task ErrorInSource7_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the eighth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the eighth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource8_PropagatedToSubscriber() { @@ -961,15 +791,15 @@ public async Task ErrorInSource8_PropagatedToSubscriber() source7, source8, source9, - (a, b, c, d, e, f, g, h, i) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}"); + static (a, b, c, d, e, f, g, h, i) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source8 error"); source8.OnError(expectedError); @@ -979,14 +809,8 @@ public async Task ErrorInSource8_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the ninth source observable is propagated to the subscriber. - /// + /// Verifies that an error in the ninth source observable is propagated to the subscriber. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task ErrorInSource9_PropagatedToSubscriber() { @@ -1009,15 +833,15 @@ public async Task ErrorInSource9_PropagatedToSubscriber() source7, source8, source9, - (a, b, c, d, e, f, g, h, i) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}"); + static (a, b, c, d, e, f, g, h, i) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}"); Exception? receivedError = null; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source9 error"); source9.OnError(expectedError); @@ -1027,14 +851,8 @@ public async Task ErrorInSource9_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that OnCompleted from a single source does not propagate completion. - /// + /// Verifies that OnCompleted from a single source does not propagate completion. /// A representing the asynchronous unit test. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Major Code Smell", - "S107:Methods should not have too many parameters", - Justification = "The combine selector lambda's parameter count equals the source arity under test.")] [Test] public async Task CompletedInSource_DoesNotPropagateCompletion() { @@ -1057,14 +875,14 @@ public async Task CompletedInSource_DoesNotPropagateCompletion() source7, source8, source9, - (a, b, c, d, e, f, g, h, i) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}"); + static (a, b, c, d, e, f, g, h, i) => $"{a}-{b}-{c}-{d}-{e}-{f}-{g}-{h}-{i}"); var completed = false; var results = new List(); - combined.Subscribe(new AnonymousObserver( + _ = combined.Subscribe(new AnonymousObserver( results.Add, - _ => { }, + static _ => { }, () => completed = true)); source1.OnNext(1); @@ -1091,15 +909,12 @@ public async Task CompletedInSource_DoesNotPropagateCompletion() await Assert.That(results).Count().IsEqualTo(1); } - /// - /// A simple observer implementation that delegates to provided action callbacks. - /// + /// A simple observer implementation that delegates to provided action callbacks. /// The type of elements observed. /// The action to invoke for each observed element. /// The action to invoke when an error occurs. /// The action to invoke when the sequence completes. - private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) - : IObserver + private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) : IObserver { /// public void OnCompleted() => onCompleted(); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/CompositeDisposable2Tests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/CompositeDisposable2Tests.cs index 93c3132..3f744ca 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/CompositeDisposable2Tests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/CompositeDisposable2Tests.cs @@ -6,14 +6,10 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Unit tests for . -/// +/// Unit tests for . public class CompositeDisposable2Tests { - /// - /// Verifies that Dispose() disposes both inner disposables. - /// + /// Verifies that Dispose() disposes both inner disposables. /// A representing the asynchronous unit test. [Test] public async Task Dispose_DisposesBothInners() @@ -30,9 +26,7 @@ public async Task Dispose_DisposesBothInners() await Assert.That(d2Disposed).IsEqualTo(1); } - /// - /// Verifies that multiple calls to Dispose() only dispose the inner disposables once. - /// + /// Verifies that multiple calls to Dispose() only dispose the inner disposables once. /// A representing the asynchronous unit test. [Test] public async Task Dispose_MultipleTimes_DisposesInnersOnlyOnce() @@ -50,26 +44,22 @@ public async Task Dispose_MultipleTimes_DisposesInnersOnlyOnce() await Assert.That(d2Disposed).IsEqualTo(1); } - /// - /// Verifies that the constructor throws when d1 is null. - /// + /// Verifies that the constructor throws when d1 is null. /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullD1_ThrowsArgumentNullException() { - var action = () => new CompositeDisposable2(null!, EmptyDisposable.Instance); + var action = static () => new CompositeDisposable2(null!, EmptyDisposable.Instance); await Assert.That(action).Throws().WithParameterName("d1"); } - /// - /// Verifies that the constructor throws when d2 is null. - /// + /// Verifies that the constructor throws when d2 is null. /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullD2_ThrowsArgumentNullException() { - var action = () => new CompositeDisposable2(EmptyDisposable.Instance, null!); + var action = static () => new CompositeDisposable2(EmptyDisposable.Instance, null!); await Assert.That(action).Throws().WithParameterName("d2"); } diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/DistinctUntilChangedObservableTests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/DistinctUntilChangedObservableTests.cs index 3379d5c..54e4635 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/DistinctUntilChangedObservableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/DistinctUntilChangedObservableTests.cs @@ -6,52 +6,40 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Unit tests for . -/// +/// Unit tests for . public class DistinctUntilChangedObservableTests { - /// - /// The expected number of distinct values emitted when consecutive duplicates are suppressed. - /// + /// The expected number of distinct values emitted when consecutive duplicates are suppressed. private const int ExpectedDistinctCount = 3; - /// - /// The second distinct integer value emitted by the source. - /// + /// The second distinct integer value emitted by the source. private const int SecondValue = 2; - /// - /// The index of the third emitted result. - /// + /// The index of the third emitted result. private const int ThirdResultIndex = 2; - /// - /// The expected number of distinct values emitted when a custom comparer is used. - /// + /// The expected number of distinct values emitted when a custom comparer is used. private const int ExpectedCustomComparerCount = 2; - /// - /// Verifies that the first value is always emitted and consecutive duplicates are suppressed. - /// + /// Verifies that the first value is always emitted and consecutive duplicates are suppressed. /// A representing the asynchronous unit test. [Test] public async Task Distinct_SuppressesConsecutiveDuplicates() { var results = new List(); - var source = new AnonymousObservable(observer => + var source = new AnonymousObservable(static observer => { observer.OnNext(1); observer.OnNext(1); - observer.OnNext(2); - observer.OnNext(2); + observer.OnNext(ExpectedCustomComparerCount); + observer.OnNext(ExpectedCustomComparerCount); observer.OnNext(1); observer.OnCompleted(); return EmptyDisposable.Instance; }); var distinct = new DistinctUntilChangedObservable(source); - distinct.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + _ = distinct.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); await Assert.That(results).Count().IsEqualTo(ExpectedDistinctCount); await Assert.That(results[0]).IsEqualTo(1); @@ -59,15 +47,13 @@ public async Task Distinct_SuppressesConsecutiveDuplicates() await Assert.That(results[ThirdResultIndex]).IsEqualTo(1); } - /// - /// Verifies that a custom IEqualityComparer is respected. - /// + /// Verifies that a custom IEqualityComparer is respected. /// A representing the asynchronous unit test. [Test] public async Task Distinct_CustomComparer_IsRespected() { var results = new List(); - var source = new AnonymousObservable(observer => + var source = new AnonymousObservable(static observer => { observer.OnNext("a"); observer.OnNext("A"); @@ -77,36 +63,32 @@ public async Task Distinct_CustomComparer_IsRespected() }); var distinct = new DistinctUntilChangedObservable(source, StringComparer.OrdinalIgnoreCase); - distinct.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + _ = distinct.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); await Assert.That(results).Count().IsEqualTo(ExpectedCustomComparerCount); await Assert.That(results[0]).IsEqualTo("a"); await Assert.That(results[1]).IsEqualTo("b"); } - /// - /// Verifies that errors from the source are forwarded. - /// + /// Verifies that errors from the source are forwarded. /// A representing the asynchronous unit test. [Test] public async Task Distinct_ForwardsError() { var errorThrown = false; - var source = new AnonymousObservable(observer => + var source = new AnonymousObservable(static observer => { observer.OnError(new InvalidOperationException("test")); return EmptyDisposable.Instance; }); var distinct = new DistinctUntilChangedObservable(source); - distinct.Subscribe(new AnonymousObserver(_ => { }, _ => errorThrown = true, () => { })); + _ = distinct.Subscribe(new AnonymousObserver(static _ => { }, _ => errorThrown = true, static () => { })); await Assert.That(errorThrown).IsTrue(); } - /// - /// Verifies that completion from the source is forwarded. - /// + /// Verifies that completion from the source is forwarded. /// A representing the asynchronous unit test. [Test] public async Task Distinct_ForwardsCompletion() @@ -115,38 +97,32 @@ public async Task Distinct_ForwardsCompletion() var source = EmptyObservable.Instance; var distinct = new DistinctUntilChangedObservable(source); - distinct.Subscribe(new AnonymousObserver(_ => { }, _ => { }, () => completed = true)); + _ = distinct.Subscribe(new AnonymousObserver(static _ => { }, static _ => { }, () => completed = true)); await Assert.That(completed).IsTrue(); } - /// - /// Verifies that the constructor throws when source is null. - /// + /// Verifies that the constructor throws when source is null. /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource_ThrowsArgumentNullException() { - var action = () => new DistinctUntilChangedObservable(null!); + var action = static () => new DistinctUntilChangedObservable(null!); await Assert.That(action).Throws().WithParameterName("source"); } - /// - /// Verifies that the constructor throws when comparer is null. - /// + /// Verifies that the constructor throws when comparer is null. /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullComparer_ThrowsArgumentNullException() { - var action = () => new DistinctUntilChangedObservable(EmptyObservable.Instance, null!); + var action = static () => new DistinctUntilChangedObservable(EmptyObservable.Instance, null!); await Assert.That(action).Throws().WithParameterName("comparer"); } - /// - /// Verifies that Subscribe throws when observer is null. - /// + /// Verifies that Subscribe throws when observer is null. /// A representing the asynchronous unit test. [Test] public async Task Subscribe_NullObserver_ThrowsArgumentNullException() @@ -157,9 +133,7 @@ public async Task Subscribe_NullObserver_ThrowsArgumentNullException() await Assert.That(action).Throws().WithParameterName("observer"); } - /// - /// A simple observable that delegates subscription to a provided function. - /// + /// A simple observable that delegates subscription to a provided function. /// The type of elements produced. /// The function to invoke when an observer subscribes. private sealed class AnonymousObservable(Func, IDisposable> subscribe) : IObservable @@ -168,15 +142,12 @@ private sealed class AnonymousObservable(Func, IDisposable> subs public IDisposable Subscribe(IObserver observer) => subscribe(observer); } - /// - /// A simple observer that delegates to provided actions. - /// + /// A simple observer that delegates to provided actions. /// The type of elements observed. /// The action to invoke for each element. /// The action to invoke on error. /// The action to invoke on completion. - private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) - : IObserver + private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) : IObserver { /// public void OnCompleted() => onCompleted(); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/EmptyObservableTests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/EmptyObservableTests.cs index 483ac9a..7bb9500 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/EmptyObservableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/EmptyObservableTests.cs @@ -6,14 +6,10 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Unit tests for . -/// +/// Unit tests for . public class EmptyObservableTests { - /// - /// Verifies that EmptyObservable completes immediately on subscribe. - /// + /// Verifies that EmptyObservable completes immediately on subscribe. /// A representing the asynchronous unit test. [Test] public async Task Subscribe_CompletesImmediately() @@ -21,25 +17,21 @@ public async Task Subscribe_CompletesImmediately() var completed = false; var results = new List(); - EmptyObservable.Instance.Subscribe(new AnonymousObserver( + _ = EmptyObservable.Instance.Subscribe(new AnonymousObserver( results.Add, - _ => { }, + static _ => { }, () => completed = true)); await Assert.That(completed).IsTrue(); await Assert.That(results).IsEmpty(); } - /// - /// Verifies that EmptyObservable throws ArgumentNullException for null observer. - /// + /// Verifies that EmptyObservable throws ArgumentNullException for null observer. [Test] public void Subscribe_NullObserver_ThrowsArgumentNullException() => - Assert.Throws(() => EmptyObservable.Instance.Subscribe(null!)); + Assert.Throws(static () => EmptyObservable.Instance.Subscribe(null!)); - /// - /// Verifies that the singleton instance is reused. - /// + /// Verifies that the singleton instance is reused. /// A representing the asynchronous unit test. [Test] public async Task Instance_IsSingleton() @@ -50,15 +42,12 @@ public async Task Instance_IsSingleton() await Assert.That(ReferenceEquals(instance1, instance2)).IsTrue(); } - /// - /// A simple observer that delegates to provided actions. - /// + /// A simple observer that delegates to provided actions. /// The type of elements observed. /// The action to invoke for each element. /// The action to invoke on error. /// The action to invoke on completion. - private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) - : IObserver + private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) : IObserver { /// public void OnCompleted() => onCompleted(); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/EventObservableTests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/EventObservableTests.cs index bc70f0f..778756f 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/EventObservableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/EventObservableTests.cs @@ -6,80 +6,66 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Unit tests for . -/// +/// Unit tests for . public class EventObservableTests { - /// - /// The initial value produced by the event observable's getter. - /// + /// The initial value produced by the event observable's getter. private const string InitialValue = "initial"; - /// - /// The expected number of emitted values when two notifications are produced. - /// + /// The expected number of emitted values when two notifications are produced. private const int ExpectedTwoEmissions = 2; - /// - /// Verifies that constructor throws ArgumentNullException when addHandler is null. - /// + /// Verifies that constructor throws ArgumentNullException when addHandler is null. /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullAddHandler_ThrowsArgumentNullException() { - var action = () => new EventObservable( + var action = static () => new EventObservable( null!, - _ => { }, - () => "test", + static _ => { }, + static () => "test", true); await Assert.That(action).ThrowsExactly(); } - /// - /// Verifies that constructor throws ArgumentNullException when removeHandler is null. - /// + /// Verifies that constructor throws ArgumentNullException when removeHandler is null. /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullRemoveHandler_ThrowsArgumentNullException() { - var action = () => new EventObservable( - _ => { }, + var action = static () => new EventObservable( + static _ => { }, null!, - () => "test", + static () => "test", true); await Assert.That(action).ThrowsExactly(); } - /// - /// Verifies that constructor throws ArgumentNullException when getter is null. - /// + /// Verifies that constructor throws ArgumentNullException when getter is null. /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullGetter_ThrowsArgumentNullException() { - var action = () => new EventObservable( - _ => { }, - _ => { }, + var action = static () => new EventObservable( + static _ => { }, + static _ => { }, null!, true); await Assert.That(action).ThrowsExactly(); } - /// - /// Verifies that Subscribe throws ArgumentNullException when observer is null. - /// + /// Verifies that Subscribe throws ArgumentNullException when observer is null. /// A representing the asynchronous unit test. [Test] public async Task Subscribe_NullObserver_ThrowsArgumentNullException() { var observable = new EventObservable( - _ => { }, - _ => { }, - () => "test", + static _ => { }, + static _ => { }, + static () => "test", true); var action = () => observable.Subscribe(null!); @@ -87,9 +73,7 @@ public async Task Subscribe_NullObserver_ThrowsArgumentNullException() await Assert.That(action).ThrowsExactly(); } - /// - /// Verifies that Subscribe emits the current value immediately. - /// + /// Verifies that Subscribe emits the current value immediately. /// A representing the asynchronous unit test. [Test] public async Task Subscribe_EmitsInitialValue() @@ -98,20 +82,18 @@ public async Task Subscribe_EmitsInitialValue() var results = new List(); var observable = new EventObservable( - _ => { }, - _ => { }, - () => value, + static _ => { }, + static _ => { }, + static () => value, false); - observable.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + _ = observable.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); await Assert.That(results).Count().IsEqualTo(1); await Assert.That(results[0]).IsEqualTo(InitialValue); } - /// - /// Verifies that event handler invocation emits updated values. - /// + /// Verifies that event handler invocation emits updated values. /// A representing the asynchronous unit test. [Test] public async Task Subscribe_EventFired_EmitsNewValue() @@ -126,7 +108,7 @@ public async Task Subscribe_EventFired_EmitsNewValue() () => value, false); - observable.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + _ = observable.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); value = "updated"; handler?.Invoke(this, EventArgs.Empty); @@ -135,9 +117,7 @@ public async Task Subscribe_EventFired_EmitsNewValue() await Assert.That(results[1]).IsEqualTo("updated"); } - /// - /// Verifies that distinct-until-changed suppresses duplicate values. - /// + /// Verifies that distinct-until-changed suppresses duplicate values. /// A representing the asynchronous unit test. [Test] public async Task Subscribe_DistinctUntilChanged_SuppressesDuplicates() @@ -152,7 +132,7 @@ public async Task Subscribe_DistinctUntilChanged_SuppressesDuplicates() () => value, true); - observable.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + _ = observable.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); // Fire event with same value — should be suppressed handler?.Invoke(this, EventArgs.Empty); @@ -167,9 +147,7 @@ public async Task Subscribe_DistinctUntilChanged_SuppressesDuplicates() await Assert.That(results[1]).IsEqualTo("different"); } - /// - /// Verifies that without distinct-until-changed, duplicate values are emitted. - /// + /// Verifies that without distinct-until-changed, duplicate values are emitted. /// A representing the asynchronous unit test. [Test] public async Task Subscribe_NoDistinct_EmitsDuplicates() @@ -181,10 +159,10 @@ public async Task Subscribe_NoDistinct_EmitsDuplicates() var observable = new EventObservable( h => handler = h, h => handler = null, - () => value, + static () => value, false); - observable.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + _ = observable.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); // Fire event with same value — should emit handler?.Invoke(this, EventArgs.Empty); @@ -192,9 +170,7 @@ public async Task Subscribe_NoDistinct_EmitsDuplicates() await Assert.That(results).Count().IsEqualTo(ExpectedTwoEmissions); } - /// - /// Verifies that Dispose unsubscribes the event handler. - /// + /// Verifies that Dispose unsubscribes the event handler. /// A representing the asynchronous unit test. [Test] public async Task Dispose_UnsubscribesHandler() @@ -214,19 +190,17 @@ public async Task Dispose_UnsubscribesHandler() handler = null; }, - () => value, + static () => value, false); - var sub = observable.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + var sub = observable.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); sub.Dispose(); await Assert.That(handler).IsNull(); } - /// - /// Verifies that events fired after dispose are ignored. - /// + /// Verifies that events fired after dispose are ignored. /// A representing the asynchronous unit test. [Test] public async Task Dispose_EventAfterDispose_Ignored() @@ -237,11 +211,11 @@ public async Task Dispose_EventAfterDispose_Ignored() var observable = new EventObservable( h => handler = h, - _ => { }, + static _ => { }, () => value, false); - var sub = observable.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + var sub = observable.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); // Keep reference before dispose clears it var savedHandler = handler; @@ -253,21 +227,19 @@ public async Task Dispose_EventAfterDispose_Ignored() await Assert.That(results).Count().IsEqualTo(1); } - /// - /// Verifies that double dispose is safe. - /// + /// Verifies that double dispose is safe. /// A representing the asynchronous unit test. [Test] public async Task Dispose_CalledTwice_IsSafe() { var removeCount = 0; var observable = new EventObservable( - _ => { }, + static _ => { }, _ => removeCount++, - () => "test", + static () => "test", false); - var sub = observable.Subscribe(new AnonymousObserver(_ => { }, _ => { }, () => { })); + var sub = observable.Subscribe(new AnonymousObserver(static _ => { }, static _ => { }, static () => { })); sub.Dispose(); sub.Dispose(); @@ -275,12 +247,12 @@ public async Task Dispose_CalledTwice_IsSafe() await Assert.That(removeCount).IsEqualTo(1); } - /// - /// Anonymous observer for testing. - /// + /// Anonymous observer for testing. /// The element type. - private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) - : IObserver + /// Called for each emitted value. + /// Called when the sequence faults. + /// Called when the sequence completes. + private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) : IObserver { /// public void OnCompleted() => onCompleted(); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/MergeObservableTests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/MergeObservableTests.cs index 47531d1..9c0163d 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/MergeObservableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/MergeObservableTests.cs @@ -7,29 +7,19 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Unit tests for edge cases. -/// +/// Unit tests for edge cases. public class MergeObservableTests { - /// - /// The value emitted by the second source observable. - /// + /// The value emitted by the second source observable. private const int SecondSourceValue = 2; - /// - /// The expected number of emitted values when both sources fire once. - /// + /// The expected number of emitted values when both sources fire once. private const int ExpectedMergedCount = 2; - /// - /// A sentinel value emitted after disposal that must not be observed. - /// + /// A sentinel value emitted after disposal that must not be observed. private const int PostDisposalValue = 99; - /// - /// Verifies that Subscribe throws ArgumentNullException when observer is null. - /// + /// Verifies that Subscribe throws ArgumentNullException when observer is null. /// A representing the asynchronous unit test. [Test] public async Task Subscribe_NullObserver_ThrowsArgumentNullException() @@ -42,21 +32,17 @@ public async Task Subscribe_NullObserver_ThrowsArgumentNullException() await Assert.That(action).ThrowsExactly(); } - /// - /// Verifies that constructor throws ArgumentNullException when sources is null. - /// + /// Verifies that constructor throws ArgumentNullException when sources is null. /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSources_ThrowsArgumentNullException() { - var action = () => new MergeObservable(null!); + var action = static () => new MergeObservable(null!); await Assert.That(action).ThrowsExactly(); } - /// - /// Verifies that an error in any source observable is propagated to the subscriber. - /// + /// Verifies that an error in any source observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task ErrorInAnySource_PropagatedToSubscriber() @@ -68,10 +54,10 @@ public async Task ErrorInAnySource_PropagatedToSubscriber() Exception? receivedError = null; var results = new List(); - merged.Subscribe(new AnonymousObserver( + _ = merged.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); source1.OnNext(1); source2.OnNext(SecondSourceValue); @@ -86,9 +72,7 @@ public async Task ErrorInAnySource_PropagatedToSubscriber() await Assert.That(receivedError).IsEqualTo(expectedError); } - /// - /// Verifies that disposal stops all emissions from merged sources. - /// + /// Verifies that disposal stops all emissions from merged sources. /// A representing the asynchronous unit test. [Test] public async Task Disposal_StopsAllEmissions() @@ -101,8 +85,8 @@ public async Task Disposal_StopsAllEmissions() var subscription = merged.Subscribe(new AnonymousObserver( results.Add, - _ => { }, - () => { })); + static _ => { }, + static () => { })); source1.OnNext(1); subscription.Dispose(); @@ -113,9 +97,7 @@ public async Task Disposal_StopsAllEmissions() await Assert.That(results[0]).IsEqualTo(1); } - /// - /// Verifies that double disposal does not throw. - /// + /// Verifies that double disposal does not throw. /// A representing the asynchronous unit test. [Test] public async Task DoubleDisposal_DoesNotThrow() @@ -127,8 +109,8 @@ public async Task DoubleDisposal_DoesNotThrow() var subscription = merged.Subscribe(new AnonymousObserver( results.Add, - _ => { }, - () => { })); + static _ => { }, + static () => { })); subscription.Dispose(); subscription.Dispose(); @@ -136,9 +118,7 @@ public async Task DoubleDisposal_DoesNotThrow() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that error from second source after first emitted is propagated. - /// + /// Verifies that error from second source after first emitted is propagated. /// A representing the asynchronous unit test. [Test] public async Task ErrorInSecondSource_AfterFirstEmitted_PropagatedToSubscriber() @@ -150,10 +130,10 @@ public async Task ErrorInSecondSource_AfterFirstEmitted_PropagatedToSubscriber() Exception? receivedError = null; var results = new List(); - merged.Subscribe(new AnonymousObserver( + _ = merged.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); source1.OnNext(1); var expectedError = new InvalidOperationException("source2 error"); @@ -164,15 +144,12 @@ public async Task ErrorInSecondSource_AfterFirstEmitted_PropagatedToSubscriber() await Assert.That(receivedError).IsEqualTo(expectedError); } - /// - /// A simple observer that delegates to provided actions. - /// + /// A simple observer that delegates to provided actions. /// The type of elements observed. /// The action to invoke for each element. /// The action to invoke on error. /// The action to invoke on completion. - private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) - : IObserver + private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) : IObserver { /// public void OnCompleted() => onCompleted(); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/PropertyChangingObservableTests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/PropertyChangingObservableTests.cs index 27149e5..62e04a1 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/PropertyChangingObservableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/PropertyChangingObservableTests.cs @@ -8,79 +8,59 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Unit tests for . -/// +/// Unit tests for . public class PropertyChangingObservableTests { - /// - /// The initial name value assigned to the view model under test. - /// + /// The initial name value assigned to the view model under test. private const string InitialName = "Alice"; - /// - /// The expected number of emissions when the initial value plus one change are observed. - /// + /// The expected number of emissions when the initial value plus one change are observed. private const int ExpectedTwoEmissions = 2; - /// - /// The expected number of emissions after a third notification. - /// + /// The expected number of emissions after a third notification. private const int ExpectedThreeEmissions = 3; - /// - /// A sample age value assigned to an unrelated property. - /// + /// A sample age value assigned to an unrelated property. private const int SampleAge = 26; - /// - /// The number of rapid property-changing iterations in the concurrency test. - /// + /// The number of rapid property-changing iterations in the concurrency test. private const int ConcurrencyIterations = 100; - /// - /// Verifies that Subscribe throws ArgumentNullException when observer is null. - /// + /// Verifies that Subscribe throws ArgumentNullException when observer is null. /// A representing the asynchronous unit test. [Test] public async Task Subscribe_NullObserver_ThrowsArgumentNullException() { var vm = new TestViewModel { Name = InitialName }; - var observable = new PropertyChangingObservable(vm, nameof(vm.Name), x => ((TestViewModel)x).Name); + var observable = new PropertyChangingObservable(vm, nameof(vm.Name), static x => ((TestViewModel)x).Name); var action = () => observable.Subscribe(null!); await Assert.That(action).ThrowsExactly(); } - /// - /// Verifies that constructor throws ArgumentNullException when source is null. - /// + /// Verifies that constructor throws ArgumentNullException when source is null. /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource_ThrowsArgumentNullException() { - var action = () => new PropertyChangingObservable(null!, "Name", x => "test"); + var action = static () => new PropertyChangingObservable(null!, "Name", static x => "test"); await Assert.That(action).ThrowsExactly(); } - /// - /// Verifies that constructor throws ArgumentNullException when propertyName is null. - /// + /// Verifies that constructor throws ArgumentNullException when propertyName is null. /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullPropertyName_ThrowsArgumentNullException() { var vm = new TestViewModel(); - var action = () => new PropertyChangingObservable(vm, null!, x => "test"); + var action = () => new PropertyChangingObservable(vm, null!, static x => "test"); await Assert.That(action).ThrowsExactly(); } - /// - /// Verifies that constructor throws ArgumentNullException when getter is null. - /// + /// Verifies that constructor throws ArgumentNullException when getter is null. /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullGetter_ThrowsArgumentNullException() @@ -91,35 +71,31 @@ public async Task Constructor_NullGetter_ThrowsArgumentNullException() await Assert.That(action).ThrowsExactly(); } - /// - /// Verifies that Subscribe emits the current value immediately. - /// + /// Verifies that Subscribe emits the current value immediately. /// A representing the asynchronous unit test. [Test] public async Task Subscribe_EmitsCurrentValueImmediately() { var vm = new TestViewModel { Name = InitialName }; var results = new List(); - var observable = new PropertyChangingObservable(vm, nameof(vm.Name), x => ((TestViewModel)x).Name); + var observable = new PropertyChangingObservable(vm, nameof(vm.Name), static x => ((TestViewModel)x).Name); - observable.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + _ = observable.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); await Assert.That(results).Count().IsEqualTo(1); await Assert.That(results[0]).IsEqualTo(InitialName); } - /// - /// Verifies that PropertyChanging event triggers a value emission (old value). - /// + /// Verifies that PropertyChanging event triggers a value emission (old value). /// A representing the asynchronous unit test. [Test] public async Task PropertyChanging_TriggersEmission() { var vm = new TestViewModel { Name = InitialName }; var results = new List(); - var observable = new PropertyChangingObservable(vm, nameof(vm.Name), x => ((TestViewModel)x).Name); + var observable = new PropertyChangingObservable(vm, nameof(vm.Name), static x => ((TestViewModel)x).Name); - observable.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + _ = observable.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); vm.Name = "Bob"; // Should have 2 values: initial "Alice", and "Alice" again when PropertyChanging fired before it became "Bob" @@ -128,36 +104,32 @@ public async Task PropertyChanging_TriggersEmission() await Assert.That(results[1]).IsEqualTo(InitialName); } - /// - /// Verifies that only matching property name triggers emission. - /// + /// Verifies that only matching property name triggers emission. /// A representing the asynchronous unit test. [Test] public async Task PropertyChanging_WrongProperty_DoesNotTriggerEmission() { - var vm = new TestViewModel { Name = InitialName, Age = 25 }; + var vm = new TestViewModel { Name = InitialName, Age = SampleAge }; var results = new List(); - var observable = new PropertyChangingObservable(vm, nameof(vm.Name), x => ((TestViewModel)x).Name); + var observable = new PropertyChangingObservable(vm, nameof(vm.Name), static x => ((TestViewModel)x).Name); - observable.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + _ = observable.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); vm.Age = SampleAge; await Assert.That(results).Count().IsEqualTo(1); await Assert.That(results[0]).IsEqualTo(InitialName); } - /// - /// Verifies that null/empty property name matches all properties. - /// + /// Verifies that null/empty property name matches all properties. /// A representing the asynchronous unit test. [Test] public async Task PropertyChanging_NullOrEmpty_TriggersEmission() { var vm = new ManualTestViewModel { Name = InitialName }; var results = new List(); - var observable = new PropertyChangingObservable(vm, "Name", x => ((ManualTestViewModel)x).Name); + var observable = new PropertyChangingObservable(vm, "Name", static x => ((ManualTestViewModel)x).Name); - observable.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + _ = observable.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); vm.RaisePropertyChanging(string.Empty); await Assert.That(results).Count().IsEqualTo(ExpectedTwoEmissions); @@ -166,18 +138,16 @@ public async Task PropertyChanging_NullOrEmpty_TriggersEmission() await Assert.That(results).Count().IsEqualTo(ExpectedThreeEmissions); } - /// - /// Verifies that disposal removes the event handler. - /// + /// Verifies that disposal removes the event handler. /// A representing the asynchronous unit test. [Test] public async Task Dispose_RemovesEventHandler() { var vm = new TestViewModel { Name = InitialName }; var results = new List(); - var observable = new PropertyChangingObservable(vm, nameof(vm.Name), x => ((TestViewModel)x).Name); + var observable = new PropertyChangingObservable(vm, nameof(vm.Name), static x => ((TestViewModel)x).Name); - var subscription = observable.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + var subscription = observable.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); subscription.Dispose(); vm.Name = "Bob"; @@ -185,35 +155,31 @@ public async Task Dispose_RemovesEventHandler() await Assert.That(results[0]).IsEqualTo(InitialName); } - /// - /// Verifies that double dispose does not throw. - /// + /// Verifies that double dispose does not throw. /// A representing the asynchronous unit test. [Test] public async Task Dispose_CalledTwice_NoException() { var vm = new TestViewModel { Name = InitialName }; - var observable = new PropertyChangingObservable(vm, nameof(vm.Name), x => ((TestViewModel)x).Name); + var observable = new PropertyChangingObservable(vm, nameof(vm.Name), static x => ((TestViewModel)x).Name); - var subscription = observable.Subscribe(new AnonymousObserver(_ => { }, _ => { }, () => { })); + var subscription = observable.Subscribe(new AnonymousObserver(static _ => { }, static _ => { }, static () => { })); subscription.Dispose(); subscription.Dispose(); await Assert.That(subscription.GetType()).IsNotNull(); } - /// - /// Verifies that a PropertyChanging event fired after dispose does not throw (observer is null path). - /// + /// Verifies that a PropertyChanging event fired after dispose does not throw (observer is null path). /// A representing the asynchronous unit test. [Test] public async Task PropertyChangingAfterDispose_DoesNotThrow() { var vm = new ManualTestViewModel { Name = InitialName }; var results = new List(); - var observable = new PropertyChangingObservable(vm, "Name", x => ((ManualTestViewModel)x).Name); + var observable = new PropertyChangingObservable(vm, "Name", static x => ((ManualTestViewModel)x).Name); - var subscription = observable.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + var subscription = observable.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); subscription.Dispose(); // Fire event after dispose - should be safely ignored @@ -235,15 +201,15 @@ public async Task OnPropertyChanging_ObserverNulledWithoutUnregistering_DoesNotT { var vm = new ManualTestViewModel { Name = InitialName }; var results = new List(); - var observable = new PropertyChangingObservable(vm, "Name", x => ((ManualTestViewModel)x).Name); + var observable = new PropertyChangingObservable(vm, "Name", static x => ((ManualTestViewModel)x).Name); - var subscription = observable.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + var subscription = observable.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); // Null the observer WITHOUT calling Dispose so the PropertyChanging event handler remains // registered — when the event fires, OnPropertyChanging runs with a null observer, // deterministically hitting the null-guard branch. TrySetDisposed performs exactly the // atomic null-out that Dispose's first step does, minus the handler unregistration. - ((PropertyChangingObservable.Subscription)subscription).TrySetDisposed(); + _ = ((PropertyChangingObservable.Subscription)subscription).TrySetDisposed(); var action = () => vm.RaisePropertyChanging("Name"); await Assert.That(action).ThrowsNothing(); @@ -266,13 +232,13 @@ public async Task PropertyChanging_ConcurrentDispose_ObserverNullGuardDoesNotThr { var vm = new ConcurrentChangingTestViewModel(); var observable = - new PropertyChangingObservable(vm, "Name", x => ((ConcurrentChangingTestViewModel)x).Name); + new PropertyChangingObservable(vm, "Name", static x => ((ConcurrentChangingTestViewModel)x).Name); var results = new List(); var subscription = observable.Subscribe(new AnonymousObserver( results.Add, - _ => { }, - () => { })); + static _ => { }, + static () => { })); // Start a background task that rapidly disposes while property changes occur var disposed = false; @@ -296,57 +262,42 @@ public async Task PropertyChanging_ConcurrentDispose_ObserverNullGuardDoesNotThr await Assert.That(results).Count().IsGreaterThanOrEqualTo(1); } - /// - /// A test view model that implements for concurrent disposal tests. - /// + /// A test view model that implements for concurrent disposal tests. private sealed class ConcurrentChangingTestViewModel : INotifyPropertyChanging { /// public event PropertyChangingEventHandler? PropertyChanging; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get; set; } = InitialName; - /// - /// Raises the event for the specified property. - /// + /// Raises the event for the specified property. /// The name of the property that is changing. public void RaisePropertyChanging(string? propertyName) => PropertyChanging?.Invoke(this, new(propertyName)); } - /// - /// A test view model that implements with manual event raising. - /// + /// A test view model that implements with manual event raising. private sealed class ManualTestViewModel : INotifyPropertyChanging { /// public event PropertyChangingEventHandler? PropertyChanging; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get; set; } = string.Empty; - /// - /// Raises the event for the specified property. - /// + /// Raises the event for the specified property. /// The name of the property that is changing. public void RaisePropertyChanging(string? propertyName) => PropertyChanging?.Invoke(this, new(propertyName)); } - /// - /// A simple observer that delegates to provided actions. - /// + /// A simple observer that delegates to provided actions. /// The type of elements observed. /// The action to invoke for each element. /// The action to invoke on error. /// The action to invoke on completion. - private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) - : IObserver + private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) : IObserver { /// public void OnCompleted() => onCompleted(); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/PropertyObservableTests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/PropertyObservableTests.cs index a1eb73a..42d65f1 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/PropertyObservableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/PropertyObservableTests.cs @@ -8,79 +8,62 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Unit tests for . -/// +/// Unit tests for . public class PropertyObservableTests { - /// - /// The initial name value assigned to the view model under test. - /// + /// How long to wait for a property notification to arrive. + private const int NotificationDelayMilliseconds = 10; + + /// The initial name value assigned to the view model under test. private const string InitialName = "Alice"; - /// - /// The expected number of emissions when the initial value plus one change are observed. - /// + /// The expected number of emissions when the initial value plus one change are observed. private const int ExpectedTwoEmissions = 2; - /// - /// The expected number of emissions after a third notification. - /// + /// The expected number of emissions after a third notification. private const int ExpectedThreeEmissions = 3; - /// - /// A sample age value assigned to an unrelated property. - /// + /// A sample age value assigned to an unrelated property. private const int SampleAge = 26; - /// - /// The number of rapid property-changed iterations in the concurrency test. - /// + /// The number of rapid property-changed iterations in the concurrency test. private const int ConcurrencyIterations = 100; - /// - /// Verifies that Subscribe throws ArgumentNullException when observer is null. - /// + /// Verifies that Subscribe throws ArgumentNullException when observer is null. /// A representing the asynchronous unit test. [Test] public async Task Subscribe_NullObserver_ThrowsArgumentNullException() { var vm = new TestViewModel { Name = InitialName }; - var observable = new PropertyObservable(vm, nameof(vm.Name), x => ((TestViewModel)x).Name, false); + var observable = new PropertyObservable(vm, nameof(vm.Name), static x => ((TestViewModel)x).Name, false); var action = () => observable.Subscribe(null!); await Assert.That(action).ThrowsExactly(); } - /// - /// Verifies that constructor throws ArgumentNullException when source is null. - /// + /// Verifies that constructor throws ArgumentNullException when source is null. /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource_ThrowsArgumentNullException() { - var action = () => new PropertyObservable(null!, "Name", x => "test", false); + var action = static () => new PropertyObservable(null!, "Name", static x => "test", false); await Assert.That(action).ThrowsExactly(); } - /// - /// Verifies that constructor throws ArgumentNullException when propertyName is null. - /// + /// Verifies that constructor throws ArgumentNullException when propertyName is null. /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullPropertyName_ThrowsArgumentNullException() { var vm = new TestViewModel(); - var action = () => new PropertyObservable(vm, null!, x => "test", false); + var action = () => new PropertyObservable(vm, null!, static x => "test", false); await Assert.That(action).ThrowsExactly(); } - /// - /// Verifies that constructor throws ArgumentNullException when getter is null. - /// + /// Verifies that constructor throws ArgumentNullException when getter is null. /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullGetter_ThrowsArgumentNullException() @@ -91,71 +74,63 @@ public async Task Constructor_NullGetter_ThrowsArgumentNullException() await Assert.That(action).ThrowsExactly(); } - /// - /// Verifies that Subscribe emits the current value immediately. - /// + /// Verifies that Subscribe emits the current value immediately. /// A representing the asynchronous unit test. [Test] public async Task Subscribe_EmitsCurrentValueImmediately() { var vm = new TestViewModel { Name = InitialName }; var results = new List(); - var observable = new PropertyObservable(vm, nameof(vm.Name), x => ((TestViewModel)x).Name, false); + var observable = new PropertyObservable(vm, nameof(vm.Name), static x => ((TestViewModel)x).Name, false); - observable.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + _ = observable.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); await Assert.That(results).Count().IsEqualTo(1); await Assert.That(results[0]).IsEqualTo(InitialName); } - /// - /// Verifies that PropertyChanged event triggers a new value emission. - /// + /// Verifies that PropertyChanged event triggers a new value emission. /// A representing the asynchronous unit test. [Test] public async Task PropertyChanged_TriggersEmission() { var vm = new TestViewModel { Name = InitialName }; var results = new List(); - var observable = new PropertyObservable(vm, nameof(vm.Name), x => ((TestViewModel)x).Name, false); + var observable = new PropertyObservable(vm, nameof(vm.Name), static x => ((TestViewModel)x).Name, false); - observable.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + _ = observable.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); vm.Name = "Bob"; await Assert.That(results).Count().IsEqualTo(ExpectedTwoEmissions); await Assert.That(results[1]).IsEqualTo("Bob"); } - /// - /// Verifies that only matching property name triggers emission. - /// + /// Verifies that only matching property name triggers emission. /// A representing the asynchronous unit test. [Test] public async Task PropertyChanged_WrongProperty_DoesNotTriggerEmission() { - var vm = new TestViewModel { Name = InitialName, Age = 25 }; + var vm = new TestViewModel { Name = InitialName, Age = SampleAge }; var results = new List(); - var observable = new PropertyObservable(vm, nameof(vm.Name), x => ((TestViewModel)x).Name, false); + var observable = new PropertyObservable(vm, nameof(vm.Name), static x => ((TestViewModel)x).Name, false); - observable.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + _ = observable.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); vm.Age = SampleAge; await Assert.That(results).Count().IsEqualTo(1); await Assert.That(results[0]).IsEqualTo(InitialName); } - /// - /// Verifies that null/empty property name matches all properties. - /// + /// Verifies that null/empty property name matches all properties. /// A representing the asynchronous unit test. [Test] public async Task PropertyChanged_NullOrEmpty_TriggersEmission() { var vm = new ManualTestViewModel { Name = InitialName }; var results = new List(); - var observable = new PropertyObservable(vm, "Name", x => ((ManualTestViewModel)x).Name, false); + var observable = new PropertyObservable(vm, "Name", static x => ((ManualTestViewModel)x).Name, false); - observable.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + _ = observable.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); vm.RaisePropertyChanged(string.Empty); await Assert.That(results).Count().IsEqualTo(ExpectedTwoEmissions); @@ -164,54 +139,48 @@ public async Task PropertyChanged_NullOrEmpty_TriggersEmission() await Assert.That(results).Count().IsEqualTo(ExpectedThreeEmissions); } - /// - /// Verifies that distinctUntilChanged=true suppresses duplicate values. - /// + /// Verifies that distinctUntilChanged=true suppresses duplicate values. /// A representing the asynchronous unit test. [Test] public async Task DistinctUntilChanged_True_SuppressesDuplicates() { var vm = new ManualTestViewModel { Name = InitialName }; var results = new List(); - var observable = new PropertyObservable(vm, "Name", x => ((ManualTestViewModel)x).Name, true); + var observable = new PropertyObservable(vm, "Name", static x => ((ManualTestViewModel)x).Name, true); - observable.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + _ = observable.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); vm.Name = InitialName; // Same value vm.RaisePropertyChanged("Name"); await Assert.That(results).Count().IsEqualTo(1); } - /// - /// Verifies that distinctUntilChanged=false allows duplicate values. - /// + /// Verifies that distinctUntilChanged=false allows duplicate values. /// A representing the asynchronous unit test. [Test] public async Task DistinctUntilChanged_False_AllowsDuplicates() { var vm = new ManualTestViewModel { Name = InitialName }; var results = new List(); - var observable = new PropertyObservable(vm, "Name", x => ((ManualTestViewModel)x).Name, false); + var observable = new PropertyObservable(vm, "Name", static x => ((ManualTestViewModel)x).Name, false); - observable.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + _ = observable.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); vm.Name = InitialName; // Same value vm.RaisePropertyChanged("Name"); await Assert.That(results).Count().IsEqualTo(ExpectedTwoEmissions); } - /// - /// Verifies that disposal removes the event handler. - /// + /// Verifies that disposal removes the event handler. /// A representing the asynchronous unit test. [Test] public async Task Dispose_RemovesEventHandler() { var vm = new TestViewModel { Name = InitialName }; var results = new List(); - var observable = new PropertyObservable(vm, nameof(vm.Name), x => ((TestViewModel)x).Name, false); + var observable = new PropertyObservable(vm, nameof(vm.Name), static x => ((TestViewModel)x).Name, false); - var subscription = observable.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + var subscription = observable.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); subscription.Dispose(); vm.Name = "Bob"; @@ -219,35 +188,31 @@ public async Task Dispose_RemovesEventHandler() await Assert.That(results[0]).IsEqualTo(InitialName); } - /// - /// Verifies that double dispose does not throw. - /// + /// Verifies that double dispose does not throw. /// A representing the asynchronous unit test. [Test] public async Task Dispose_CalledTwice_NoException() { var vm = new TestViewModel { Name = InitialName }; - var observable = new PropertyObservable(vm, nameof(vm.Name), x => ((TestViewModel)x).Name, false); + var observable = new PropertyObservable(vm, nameof(vm.Name), static x => ((TestViewModel)x).Name, false); - var subscription = observable.Subscribe(new AnonymousObserver(_ => { }, _ => { }, () => { })); + var subscription = observable.Subscribe(new AnonymousObserver(static _ => { }, static _ => { }, static () => { })); subscription.Dispose(); subscription.Dispose(); await Assert.That(subscription.GetType()).IsNotNull(); } - /// - /// Verifies that a PropertyChanged event fired after dispose does not throw (observer is null path). - /// + /// Verifies that a PropertyChanged event fired after dispose does not throw (observer is null path). /// A representing the asynchronous unit test. [Test] public async Task PropertyChangedAfterDispose_DoesNotThrow() { var vm = new ManualTestViewModel { Name = InitialName }; var results = new List(); - var observable = new PropertyObservable(vm, "Name", x => ((ManualTestViewModel)x).Name, false); + var observable = new PropertyObservable(vm, "Name", static x => ((ManualTestViewModel)x).Name, false); - var subscription = observable.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + var subscription = observable.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); subscription.Dispose(); // Fire event after dispose - should be safely ignored @@ -269,15 +234,15 @@ public async Task OnPropertyChanged_ObserverNulledWithoutUnregistering_DoesNotTh { var vm = new ManualTestViewModel { Name = InitialName }; var results = new List(); - var observable = new PropertyObservable(vm, "Name", x => ((ManualTestViewModel)x).Name, false); + var observable = new PropertyObservable(vm, "Name", static x => ((ManualTestViewModel)x).Name, false); - var subscription = observable.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + var subscription = observable.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); // Null the observer WITHOUT calling Dispose so the PropertyChanged event handler remains // registered — when the event fires, OnPropertyChanged runs with a null observer, // deterministically hitting the null-guard branch. TrySetDisposed performs exactly the // atomic null-out that Dispose's first step does, minus the handler unregistration. - ((PropertyObservable.Subscription)subscription).TrySetDisposed(); + _ = ((PropertyObservable.Subscription)subscription).TrySetDisposed(); var action = () => vm.RaisePropertyChanged("Name"); await Assert.That(action).ThrowsNothing(); @@ -299,19 +264,19 @@ public async Task OnPropertyChanged_ObserverNulledWithoutUnregistering_DoesNotTh public async Task PropertyChanged_ConcurrentDispose_ObserverNullGuardDoesNotThrow() { var vm = new ConcurrentTestViewModel(); - var observable = new PropertyObservable(vm, "Name", x => ((ConcurrentTestViewModel)x).Name, false); + var observable = new PropertyObservable(vm, "Name", static x => ((ConcurrentTestViewModel)x).Name, false); var results = new List(); var subscription = observable.Subscribe(new AnonymousObserver( results.Add, - _ => { }, - () => { })); + static _ => { }, + static () => { })); // Start a background task that rapidly disposes while property changes occur var disposed = false; var disposeTask = Task.Run(async () => { - await Task.Delay(10); + await Task.Delay(NotificationDelayMilliseconds); subscription.Dispose(); disposed = true; }); @@ -329,57 +294,42 @@ public async Task PropertyChanged_ConcurrentDispose_ObserverNullGuardDoesNotThro await Assert.That(results).Count().IsGreaterThanOrEqualTo(1); } - /// - /// A test view model that implements for concurrent disposal tests. - /// + /// A test view model that implements for concurrent disposal tests. private sealed class ConcurrentTestViewModel : INotifyPropertyChanged { /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get; set; } = InitialName; - /// - /// Raises the event for the specified property. - /// + /// Raises the event for the specified property. /// The name of the property that changed. public void RaisePropertyChanged(string? propertyName) => PropertyChanged?.Invoke(this, new(propertyName)); } - /// - /// A test view model that implements with manual event raising. - /// + /// A test view model that implements with manual event raising. private sealed class ManualTestViewModel : INotifyPropertyChanged { /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get; set; } = string.Empty; - /// - /// Raises the event for the specified property. - /// + /// Raises the event for the specified property. /// The name of the property that changed. public void RaisePropertyChanged(string? propertyName) => PropertyChanged?.Invoke(this, new(propertyName)); } - /// - /// A simple observer that delegates to provided actions. - /// + /// A simple observer that delegates to provided actions. /// The type of elements observed. /// The action to invoke for each element. /// The action to invoke on error. /// The action to invoke on completion. - private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) - : IObserver + private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) : IObserver { /// public void OnCompleted() => onCompleted(); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/ReturnObservableTests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/ReturnObservableTests.cs index c930605..d8152de 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/ReturnObservableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/ReturnObservableTests.cs @@ -6,19 +6,13 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Unit tests for . -/// +/// Unit tests for . public class ReturnObservableTests { - /// - /// The value produced by the return observable under test. - /// + /// The value produced by the return observable under test. private const int ExpectedValue = 42; - /// - /// Verifies that Subscribe emits the single value and then completes. - /// + /// Verifies that Subscribe emits the single value and then completes. /// A representing the asynchronous unit test. [Test] public async Task Subscribe_EmitsValueAndCompletes() @@ -27,7 +21,7 @@ public async Task Subscribe_EmitsValueAndCompletes() var completed = false; var observer = new AnonymousObserver( v => nextValue = v, - _ => { }, + static _ => { }, () => completed = true); var observable = new ReturnObservable(ExpectedValue); @@ -38,9 +32,7 @@ public async Task Subscribe_EmitsValueAndCompletes() await Assert.That(disposable).IsEqualTo(EmptyDisposable.Instance); } - /// - /// Verifies that Subscribe works with null values for reference types. - /// + /// Verifies that Subscribe works with null values for reference types. /// A representing the asynchronous unit test. [Test] public async Task Subscribe_WithNullValue_EmitsNullAndCompletes() @@ -49,38 +41,33 @@ public async Task Subscribe_WithNullValue_EmitsNullAndCompletes() var completed = false; var observer = new AnonymousObserver( v => nextValue = v, - _ => { }, + static _ => { }, () => completed = true); var observable = new ReturnObservable(null); - observable.Subscribe(observer); + _ = observable.Subscribe(observer); await Assert.That(nextValue).IsNull(); await Assert.That(completed).IsTrue(); } - /// - /// Verifies that Subscribe throws ArgumentNullException when observer is null. - /// + /// Verifies that Subscribe throws ArgumentNullException when observer is null. /// A representing the asynchronous unit test. [Test] public async Task Subscribe_NullObserver_ThrowsArgumentNullException() { - var observable = new ReturnObservable(42); + var observable = new ReturnObservable(ExpectedValue); var action = () => observable.Subscribe(null!); await Assert.That(action).Throws().WithParameterName("observer"); } - /// - /// A simple observer that delegates to provided actions. - /// + /// A simple observer that delegates to provided actions. /// The type of elements observed. /// The action to invoke for each element. /// The action to invoke on error. /// The action to invoke on completion. - private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) - : IObserver + private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) : IObserver { /// public void OnCompleted() => onCompleted(); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/RxBindingExtensionsTests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/RxBindingExtensionsTests.cs index 43f6fc0..92a38df 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/RxBindingExtensionsTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/RxBindingExtensionsTests.cs @@ -7,29 +7,19 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Unit tests for . -/// +/// Unit tests for . public class RxBindingExtensionsTests { - /// - /// The value produced by the return observable used across tests. - /// + /// The value produced by the return observable used across tests. private const int ReturnedValue = 42; - /// - /// The expected number of emitted values when two notifications are produced. - /// + /// The expected number of emitted values when two notifications are produced. private const int ExpectedTwoEmissions = 2; - /// - /// The second integer value emitted by a source observable. - /// + /// The second integer value emitted by a source observable. private const int SecondValue = 2; - /// - /// Verifies that Subscribe invokes the action for each value. - /// + /// Verifies that Subscribe invokes the action for each value. /// A representing the asynchronous unit test. [Test] public async Task Subscribe_InvokesAction() @@ -37,15 +27,13 @@ public async Task Subscribe_InvokesAction() var results = new List(); var source = new ReturnObservable(ReturnedValue); - RxBinding.Subscribe(source, results.Add); + _ = RxBinding.Subscribe(source, results.Add); await Assert.That(results).Count().IsEqualTo(1); await Assert.That(results[0]).IsEqualTo(ReturnedValue); } - /// - /// Verifies that Select applies the projection correctly. - /// + /// Verifies that Select applies the projection correctly. /// A representing the asynchronous unit test. [Test] public async Task Select_AppliesProjection() @@ -53,94 +41,86 @@ public async Task Select_AppliesProjection() var results = new List(); var source = new ReturnObservable(ReturnedValue); - var select = RxBinding.Select(source, x => x.ToString()); - select.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + var select = RxBinding.Select(source, static x => x.ToString()); + _ = select.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); await Assert.That(results).Count().IsEqualTo(1); await Assert.That(results[0]).IsEqualTo("42"); } - /// - /// Verifies that Skip delegates to SkipObservable. - /// + /// Verifies that Skip delegates to SkipObservable. /// A representing the asynchronous unit test. [Test] public async Task Skip_DelegatesToSkipObservable() { var results = new List(); - var source = new AnonymousObservable(observer => + var source = new AnonymousObservable(static observer => { observer.OnNext(1); - observer.OnNext(2); + observer.OnNext(SecondValue); return EmptyDisposable.Instance; }); var skip = RxBinding.Skip(source, 1); - skip.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + _ = skip.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); await Assert.That(results).Count().IsEqualTo(1); await Assert.That(results[0]).IsEqualTo(SecondValue); } - /// - /// Verifies that DistinctUntilChanged delegates to DistinctUntilChangedObservable. - /// + /// Verifies that DistinctUntilChanged delegates to DistinctUntilChangedObservable. /// A representing the asynchronous unit test. [Test] public async Task DistinctUntilChanged_DelegatesToDistinctUntilChangedObservable() { var results = new List(); - var source = new AnonymousObservable(observer => + var source = new AnonymousObservable(static observer => { observer.OnNext(1); observer.OnNext(1); - observer.OnNext(2); + observer.OnNext(SecondValue); return EmptyDisposable.Instance; }); var distinct = RxBinding.DistinctUntilChanged(source); - distinct.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + _ = distinct.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); await Assert.That(results).Count().IsEqualTo(ExpectedTwoEmissions); await Assert.That(results[0]).IsEqualTo(1); await Assert.That(results[1]).IsEqualTo(SecondValue); } - /// - /// Verifies that Merge merges multiple observables. - /// + /// Verifies that Merge merges multiple observables. /// A representing the asynchronous unit test. [Test] public async Task Merge_MergesMultipleObservables() { var results = new List(); var s1 = new ReturnObservable(1); - var s2 = new ReturnObservable(2); + var s2 = new ReturnObservable(SecondValue); var merged = RxBinding.Merge(s1, s2); - merged.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + _ = merged.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); await Assert.That(results).Count().IsEqualTo(ExpectedTwoEmissions); await Assert.That(results).Contains(1); await Assert.That(results).Contains(SecondValue); } - /// - /// Verifies that Switch switches to the newest inner observable. - /// + /// Verifies that Switch switches to the newest inner observable. /// A representing the asynchronous unit test. [Test] public async Task Switch_SwitchesToNewestObservable() { var results = new List(); - var inner1 = new AnonymousObservable(observer => + var inner1 = new AnonymousObservable(static observer => { observer.OnNext(1); return EmptyDisposable.Instance; }); - var inner2 = new AnonymousObservable(observer => + var inner2 = new AnonymousObservable(static observer => { - observer.OnNext(2); + observer.OnNext(SecondValue); return EmptyDisposable.Instance; }); @@ -152,40 +132,34 @@ public async Task Switch_SwitchesToNewestObservable() }); var switched = RxBinding.Switch(source); - switched.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + _ = switched.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); await Assert.That(results).Count().IsEqualTo(ExpectedTwoEmissions); await Assert.That(results[0]).IsEqualTo(1); await Assert.That(results[1]).IsEqualTo(SecondValue); } - /// - /// Verifies that Subscribe throws ArgumentNullException when source is null. - /// + /// Verifies that Subscribe throws ArgumentNullException when source is null. /// A representing the asynchronous unit test. [Test] public async Task Subscribe_NullSource_ThrowsArgumentNullException() { - var action = () => RxBinding.Subscribe(null!, _ => { }); + var action = static () => RxBinding.Subscribe(null!, static _ => { }); await Assert.That(action).Throws().WithParameterName("source"); } - /// - /// Verifies that Subscribe throws ArgumentNullException when onNext is null. - /// + /// Verifies that Subscribe throws ArgumentNullException when onNext is null. /// A representing the asynchronous unit test. [Test] public async Task Subscribe_NullOnNext_ThrowsArgumentNullException() { - var action = () => RxBinding.Subscribe(EmptyObservable.Instance, null!); + var action = static () => RxBinding.Subscribe(EmptyObservable.Instance, null!); await Assert.That(action).Throws().WithParameterName("onNext"); } - /// - /// A simple observable that delegates subscription to a provided function. - /// + /// A simple observable that delegates subscription to a provided function. /// The type of elements produced. /// The function to invoke when an observer subscribes. private sealed class AnonymousObservable(Func, IDisposable> subscribe) : IObservable @@ -194,15 +168,12 @@ private sealed class AnonymousObservable(Func, IDisposable> subs public IDisposable Subscribe(IObserver observer) => subscribe(observer); } - /// - /// A simple observer that delegates to provided actions. - /// + /// A simple observer that delegates to provided actions. /// The type of elements observed. /// The action to invoke for each element. /// The action to invoke on error. /// The action to invoke on completion. - private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) - : IObserver + private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) : IObserver { /// public void OnCompleted() => onCompleted(); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/SelectObservableTests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/SelectObservableTests.cs index 07f884e..8980ba1 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/SelectObservableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/SelectObservableTests.cs @@ -7,53 +7,39 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Unit tests for edge cases. -/// +/// Unit tests for edge cases. public class SelectObservableTests { - /// - /// The first value pushed through the source observable. - /// + /// The first value pushed through the source observable. private const int FirstInput = 5; - /// - /// The second value pushed through the source observable. - /// + /// The second value pushed through the source observable. private const int SecondInput = 10; - /// - /// The expected number of projected results. - /// + /// The expected number of projected results. private const int ExpectedResultCount = 2; - /// - /// The expected first projected result (first input doubled). - /// + /// The expected first projected result (first input doubled). private const int FirstExpectedResult = 10; - /// - /// The expected second projected result (second input doubled). - /// + /// The expected second projected result (second input doubled). private const int SecondExpectedResult = 20; - /// - /// Verifies that error propagates through Select. - /// + /// Verifies that error propagates through Select. /// A representing the asynchronous unit test. [Test] public async Task ErrorInSource_PropagatedToSubscriber() { var source = new Subject(); - var selectObs = new SelectObservable(source, x => x.ToString()); + var selectObs = new SelectObservable(source, static x => x.ToString()); Exception? receivedError = null; var results = new List(); - selectObs.Subscribe(new AnonymousObserver( + _ = selectObs.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("source error"); source.OnError(expectedError); @@ -63,22 +49,20 @@ public async Task ErrorInSource_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that completion propagates through Select. - /// + /// Verifies that completion propagates through Select. /// A representing the asynchronous unit test. [Test] public async Task Completion_PropagatedToSubscriber() { var source = new Subject(); - var selectObs = new SelectObservable(source, x => x.ToString()); + var selectObs = new SelectObservable(source, static x => x.ToString()); var completed = false; var results = new List(); - selectObs.Subscribe(new AnonymousObserver( + _ = selectObs.Subscribe(new AnonymousObserver( results.Add, - _ => { }, + static _ => { }, () => completed = true)); source.OnNext(1); @@ -89,36 +73,30 @@ public async Task Completion_PropagatedToSubscriber() await Assert.That(results[0]).IsEqualTo("1"); } - /// - /// Verifies that Subscribe throws ArgumentNullException when observer is null. - /// + /// Verifies that Subscribe throws ArgumentNullException when observer is null. /// A representing the asynchronous unit test. [Test] public async Task Subscribe_NullObserver_ThrowsArgumentNullException() { var source = new Subject(); - var selectObs = new SelectObservable(source, x => x.ToString()); + var selectObs = new SelectObservable(source, static x => x.ToString()); var action = () => selectObs.Subscribe(null!); await Assert.That(action).ThrowsExactly(); } - /// - /// Verifies that constructor throws ArgumentNullException when source is null. - /// + /// Verifies that constructor throws ArgumentNullException when source is null. /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource_ThrowsArgumentNullException() { - var action = () => new SelectObservable(null!, x => x.ToString()); + var action = static () => new SelectObservable(null!, static x => x.ToString()); await Assert.That(action).ThrowsExactly(); } - /// - /// Verifies that constructor throws ArgumentNullException when selector is null. - /// + /// Verifies that constructor throws ArgumentNullException when selector is null. /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSelector_ThrowsArgumentNullException() @@ -129,22 +107,20 @@ public async Task Constructor_NullSelector_ThrowsArgumentNullException() await Assert.That(action).ThrowsExactly(); } - /// - /// Verifies that a selector function transforms values correctly. - /// + /// Verifies that a selector function transforms values correctly. /// A representing the asynchronous unit test. [Test] public async Task Selector_TransformsValues() { var source = new Subject(); - var selectObs = new SelectObservable(source, x => x * 2); + var selectObs = new SelectObservable(source, static x => x * ExpectedResultCount); var results = new List(); - selectObs.Subscribe(new AnonymousObserver( + _ = selectObs.Subscribe(new AnonymousObserver( results.Add, - _ => { }, - () => { })); + static _ => { }, + static () => { })); source.OnNext(FirstInput); source.OnNext(SecondInput); @@ -154,15 +130,12 @@ public async Task Selector_TransformsValues() await Assert.That(results[1]).IsEqualTo(SecondExpectedResult); } - /// - /// A simple observer that delegates to provided actions. - /// + /// A simple observer that delegates to provided actions. /// The type of elements observed. /// The action to invoke for each element. /// The action to invoke on error. /// The action to invoke on completion. - private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) - : IObserver + private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) : IObserver { /// public void OnCompleted() => onCompleted(); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/SerialDisposableTests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/SerialDisposableTests.cs index 23b7c53..adcb9ce 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/SerialDisposableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/SerialDisposableTests.cs @@ -7,14 +7,10 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Tests for . -/// +/// Tests for . public class SerialDisposableTests { - /// - /// Verifies that setting a new disposable disposes the previous one. - /// + /// Verifies that setting a new disposable disposes the previous one. /// A representing the asynchronous unit test. [Test] public async Task SetDisposable_DisposesPrevious() @@ -30,9 +26,7 @@ public async Task SetDisposable_DisposesPrevious() await Assert.That(disposed2).IsEqualTo(0); } - /// - /// Verifies that disposing the serial disposable disposes the current inner. - /// + /// Verifies that disposing the serial disposable disposes the current inner. /// A representing the asynchronous unit test. [Test] public async Task Dispose_DisposesInner() @@ -45,9 +39,7 @@ public async Task Dispose_DisposesInner() await Assert.That(disposed).IsEqualTo(1); } - /// - /// Verifies that setting a disposable after the serial is disposed, disposes it immediately. - /// + /// Verifies that setting a disposable after the serial is disposed, disposes it immediately. /// A representing the asynchronous unit test. [Test] public async Task SetAfterDispose_DisposesImmediately() @@ -60,9 +52,7 @@ public async Task SetAfterDispose_DisposesImmediately() await Assert.That(disposed).IsEqualTo(1); } - /// - /// Verifies that disposing twice does not double-dispose the inner. - /// + /// Verifies that disposing twice does not double-dispose the inner. /// A representing the asynchronous unit test. [Test] public async Task Dispose_Twice_NoDoubleFree() @@ -76,9 +66,7 @@ public async Task Dispose_Twice_NoDoubleFree() await Assert.That(disposed).IsEqualTo(1); } - /// - /// Verifies that the Disposable getter returns the currently set disposable. - /// + /// Verifies that the Disposable getter returns the currently set disposable. /// A representing the asynchronous unit test. [Test] public async Task Disposable_Getter_ReturnsCurrentValue() @@ -86,14 +74,12 @@ public async Task Disposable_Getter_ReturnsCurrentValue() var serial = new SerialDisposable(); await Assert.That(serial.Disposable).IsNull(); - var inner = new ActionDisposable(() => { }); + var inner = new ActionDisposable(static () => { }); serial.Disposable = inner; await Assert.That(serial.Disposable).IsSameReferenceAs(inner); } - /// - /// Verifies that setting Disposable to null disposes the old value. - /// + /// Verifies that setting Disposable to null disposes the old value. /// A representing the asynchronous unit test. [Test] public async Task SetToNull_DisposesOldValue() diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/SkipObservableTests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/SkipObservableTests.cs index 7954456..b25ac2f 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/SkipObservableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/SkipObservableTests.cs @@ -6,101 +6,94 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Unit tests for . -/// +/// Unit tests for . public class SkipObservableTests { - /// - /// The single value produced by the source observable in single-item tests. - /// + /// The second value emitted by the source sequence. + private const int SecondValue = 2; + + /// A skip count larger than the number of items the source emits. + private const int SkipBeyondCount = 5; + + /// The number of leading items to skip. + private const int SkipCount = 2; + + /// The single value produced by the source observable in single-item tests. private const int SingleValue = 42; - /// - /// The last value emitted after skipping the first items in the multi-item test. - /// + /// The last value emitted after skipping the first items in the multi-item test. private const int LastEmittedValue = 3; - /// - /// Verifies that Skip(0) forwards all items. - /// + /// Verifies that Skip(0) forwards all items. /// A representing the asynchronous unit test. [Test] public async Task Skip_Zero_ForwardsAllItems() { var results = new List(); - var source = new ReturnObservable(42); + var source = new ReturnObservable(SingleValue); var skip = new SkipObservable(source, 0); - skip.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + _ = skip.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); await Assert.That(results).Count().IsEqualTo(1); await Assert.That(results[0]).IsEqualTo(SingleValue); } - /// - /// Verifies that Skip(N) skips first N items and forwards the rest. - /// + /// Verifies that Skip(N) skips first N items and forwards the rest. /// A representing the asynchronous unit test. [Test] public async Task Skip_N_SkipsFirstNItems() { var results = new List(); - var source = new AnonymousObservable(observer => + var source = new AnonymousObservable(static observer => { observer.OnNext(1); - observer.OnNext(2); - observer.OnNext(3); + observer.OnNext(SecondValue); + observer.OnNext(LastEmittedValue); observer.OnCompleted(); return EmptyDisposable.Instance; }); - var skip = new SkipObservable(source, 2); - skip.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + var skip = new SkipObservable(source, SkipCount); + _ = skip.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); await Assert.That(results).Count().IsEqualTo(1); await Assert.That(results[0]).IsEqualTo(LastEmittedValue); } - /// - /// Verifies that Skip(N) forwards no items when N is greater than total items. - /// + /// Verifies that Skip(N) forwards no items when N is greater than total items. /// A representing the asynchronous unit test. [Test] public async Task Skip_NGreaterThanTotal_ForwardsNoItems() { var results = new List(); - var source = new ReturnObservable(42); - var skip = new SkipObservable(source, 5); + var source = new ReturnObservable(SingleValue); + var skip = new SkipObservable(source, SkipBeyondCount); - skip.Subscribe(new AnonymousObserver(results.Add, _ => { }, () => { })); + _ = skip.Subscribe(new AnonymousObserver(results.Add, static _ => { }, static () => { })); await Assert.That(results).IsEmpty(); } - /// - /// Verifies that Skip(N) forwards errors from the source. - /// + /// Verifies that Skip(N) forwards errors from the source. /// A representing the asynchronous unit test. [Test] public async Task Skip_ForwardsError() { var errorThrown = false; - var source = new AnonymousObservable(observer => + var source = new AnonymousObservable(static observer => { observer.OnError(new InvalidOperationException("test")); return EmptyDisposable.Instance; }); var skip = new SkipObservable(source, 1); - skip.Subscribe(new AnonymousObserver(_ => { }, _ => errorThrown = true, () => { })); + _ = skip.Subscribe(new AnonymousObserver(static _ => { }, _ => errorThrown = true, static () => { })); await Assert.That(errorThrown).IsTrue(); } - /// - /// Verifies that Skip(N) forwards completion from the source. - /// + /// Verifies that Skip(N) forwards completion from the source. /// A representing the asynchronous unit test. [Test] public async Task Skip_ForwardsCompletion() @@ -109,26 +102,22 @@ public async Task Skip_ForwardsCompletion() var source = EmptyObservable.Instance; var skip = new SkipObservable(source, 1); - skip.Subscribe(new AnonymousObserver(_ => { }, _ => { }, () => completed = true)); + _ = skip.Subscribe(new AnonymousObserver(static _ => { }, static _ => { }, () => completed = true)); await Assert.That(completed).IsTrue(); } - /// - /// Verifies that the constructor throws when source is null. - /// + /// Verifies that the constructor throws when source is null. /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource_ThrowsArgumentNullException() { - var action = () => new SkipObservable(null!, 1); + var action = static () => new SkipObservable(null!, 1); await Assert.That(action).Throws().WithParameterName("source"); } - /// - /// Verifies that Subscribe throws when observer is null. - /// + /// Verifies that Subscribe throws when observer is null. /// A representing the asynchronous unit test. [Test] public async Task Subscribe_NullObserver_ThrowsArgumentNullException() @@ -139,9 +128,7 @@ public async Task Subscribe_NullObserver_ThrowsArgumentNullException() await Assert.That(action).Throws().WithParameterName("observer"); } - /// - /// A simple observable that delegates subscription to a provided function. - /// + /// A simple observable that delegates subscription to a provided function. /// The type of elements produced. /// The function to invoke when an observer subscribes. private sealed class AnonymousObservable(Func, IDisposable> subscribe) : IObservable @@ -150,15 +137,12 @@ private sealed class AnonymousObservable(Func, IDisposable> subs public IDisposable Subscribe(IObserver observer) => subscribe(observer); } - /// - /// A simple observer that delegates to provided actions. - /// + /// A simple observer that delegates to provided actions. /// The type of elements observed. /// The action to invoke for each element. /// The action to invoke on error. /// The action to invoke on completion. - private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) - : IObserver + private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) : IObserver { /// public void OnCompleted() => onCompleted(); diff --git a/src/tests/ReactiveUI.Binding.Tests/Observables/SwitchObservableTests.cs b/src/tests/ReactiveUI.Binding.Tests/Observables/SwitchObservableTests.cs index 344d453..b6ea2a3 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Observables/SwitchObservableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Observables/SwitchObservableTests.cs @@ -7,34 +7,22 @@ namespace ReactiveUI.Binding.Tests.Observables; -/// -/// Unit tests for edge cases. -/// +/// Unit tests for edge cases. public class SwitchObservableTests { - /// - /// A generic value emitted by an inner observable in tests. - /// + /// A generic value emitted by an inner observable in tests. private const int SampleValue = 42; - /// - /// A value emitted from a disposed inner observable that must be ignored. - /// + /// A value emitted from a disposed inner observable that must be ignored. private const int IgnoredValue = 99; - /// - /// The value emitted by the second inner observable. - /// + /// The value emitted by the second inner observable. private const int SecondInnerValue = 2; - /// - /// The expected number of emitted values when two inner emissions are received. - /// + /// The expected number of emitted values when two inner emissions are received. private const int ExpectedTwoEmissions = 2; - /// - /// Verifies that Subscribe throws ArgumentNullException when observer is null. - /// + /// Verifies that Subscribe throws ArgumentNullException when observer is null. /// A representing the asynchronous unit test. [Test] public async Task Subscribe_NullObserver_ThrowsArgumentNullException() @@ -47,21 +35,17 @@ public async Task Subscribe_NullObserver_ThrowsArgumentNullException() await Assert.That(action).ThrowsExactly(); } - /// - /// Verifies that constructor throws ArgumentNullException when source is null. - /// + /// Verifies that constructor throws ArgumentNullException when source is null. /// A representing the asynchronous unit test. [Test] public async Task Constructor_NullSource_ThrowsArgumentNullException() { - var action = () => new SwitchObservable(null!); + var action = static () => new SwitchObservable(null!); await Assert.That(action).ThrowsExactly(); } - /// - /// Verifies that an error in the outer observable is propagated to the subscriber. - /// + /// Verifies that an error in the outer observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task OuterError_PropagatedToSubscriber() @@ -72,10 +56,10 @@ public async Task OuterError_PropagatedToSubscriber() Exception? receivedError = null; var results = new List(); - switchObs.Subscribe(new AnonymousObserver( + _ = switchObs.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); var expectedError = new InvalidOperationException("outer error"); outerSubject.OnError(expectedError); @@ -85,9 +69,7 @@ public async Task OuterError_PropagatedToSubscriber() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that an error in the inner observable is propagated to the subscriber. - /// + /// Verifies that an error in the inner observable is propagated to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task InnerError_PropagatedToSubscriber() @@ -99,10 +81,10 @@ public async Task InnerError_PropagatedToSubscriber() Exception? receivedError = null; var results = new List(); - switchObs.Subscribe(new AnonymousObserver( + _ = switchObs.Subscribe(new AnonymousObserver( results.Add, ex => receivedError = ex, - () => { })); + static () => { })); outerSubject.OnNext(innerSubject); innerSubject.OnNext(SampleValue); @@ -116,9 +98,7 @@ public async Task InnerError_PropagatedToSubscriber() await Assert.That(receivedError).IsEqualTo(expectedError); } - /// - /// Verifies that rapid switching (new inner before old completes) causes only the latest inner to emit. - /// + /// Verifies that rapid switching (new inner before old completes) causes only the latest inner to emit. /// A representing the asynchronous unit test. [Test] public async Task RapidSwitching_OnlyLatestInnerEmits() @@ -130,10 +110,10 @@ public async Task RapidSwitching_OnlyLatestInnerEmits() var results = new List(); - switchObs.Subscribe(new AnonymousObserver( + _ = switchObs.Subscribe(new AnonymousObserver( results.Add, - _ => { }, - () => { })); + static _ => { }, + static () => { })); // Subscribe to first inner outerSubject.OnNext(inner1); @@ -153,9 +133,7 @@ public async Task RapidSwitching_OnlyLatestInnerEmits() await Assert.That(results[1]).IsEqualTo(SecondInnerValue); } - /// - /// Verifies that disposal during an active inner subscription stops all emissions. - /// + /// Verifies that disposal during an active inner subscription stops all emissions. /// A representing the asynchronous unit test. [Test] public async Task Disposal_DuringActiveInner_NoMoreEmissions() @@ -168,8 +146,8 @@ public async Task Disposal_DuringActiveInner_NoMoreEmissions() var subscription = switchObs.Subscribe(new AnonymousObserver( results.Add, - _ => { }, - () => { })); + static _ => { }, + static () => { })); outerSubject.OnNext(innerSubject); innerSubject.OnNext(1); @@ -185,9 +163,7 @@ public async Task Disposal_DuringActiveInner_NoMoreEmissions() await Assert.That(results[0]).IsEqualTo(1); } - /// - /// Verifies that null inner observable is handled gracefully (no subscription). - /// + /// Verifies that null inner observable is handled gracefully (no subscription). /// A representing the asynchronous unit test. [Test] public async Task NullInnerObservable_IsIgnored() @@ -197,19 +173,17 @@ public async Task NullInnerObservable_IsIgnored() var results = new List(); - switchObs.Subscribe(new AnonymousObserver( + _ = switchObs.Subscribe(new AnonymousObserver( results.Add, - _ => { }, - () => { })); + static _ => { }, + static () => { })); outerSubject.OnNext(null!); await Assert.That(results).IsEmpty(); } - /// - /// Verifies that double disposal does not throw. - /// + /// Verifies that double disposal does not throw. /// A representing the asynchronous unit test. [Test] public async Task DoubleDisposal_DoesNotThrow() @@ -221,8 +195,8 @@ public async Task DoubleDisposal_DoesNotThrow() var subscription = switchObs.Subscribe(new AnonymousObserver( results.Add, - _ => { }, - () => { })); + static _ => { }, + static () => { })); subscription.Dispose(); subscription.Dispose(); @@ -230,9 +204,7 @@ public async Task DoubleDisposal_DoesNotThrow() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that outer OnCompleted does not terminate the subscription. - /// + /// Verifies that outer OnCompleted does not terminate the subscription. /// A representing the asynchronous unit test. [Test] public async Task OuterCompleted_InnerStillEmits() @@ -243,10 +215,10 @@ public async Task OuterCompleted_InnerStillEmits() var results = new List(); - switchObs.Subscribe(new AnonymousObserver( + _ = switchObs.Subscribe(new AnonymousObserver( results.Add, - _ => { }, - () => { })); + static _ => { }, + static () => { })); outerSubject.OnNext(innerSubject); outerSubject.OnCompleted(); @@ -258,9 +230,7 @@ public async Task OuterCompleted_InnerStillEmits() await Assert.That(results[0]).IsEqualTo(SampleValue); } - /// - /// Verifies that outer OnNext after dispose is ignored. - /// + /// Verifies that outer OnNext after dispose is ignored. /// A representing the asynchronous unit test. [Test] public async Task OuterOnNextAfterDispose_IsIgnored() @@ -272,8 +242,8 @@ public async Task OuterOnNextAfterDispose_IsIgnored() var subscription = switchObs.Subscribe(new AnonymousObserver( results.Add, - _ => { }, - () => { })); + static _ => { }, + static () => { })); subscription.Dispose(); @@ -283,9 +253,7 @@ public async Task OuterOnNextAfterDispose_IsIgnored() await Assert.That(results).IsEmpty(); } - /// - /// Verifies that outer error after dispose is ignored. - /// + /// Verifies that outer error after dispose is ignored. /// A representing the asynchronous unit test. [Test] public async Task OuterErrorAfterDispose_IsIgnored() @@ -296,9 +264,9 @@ public async Task OuterErrorAfterDispose_IsIgnored() Exception? receivedError = null; var subscription = switchObs.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); subscription.Dispose(); @@ -308,9 +276,7 @@ public async Task OuterErrorAfterDispose_IsIgnored() await Assert.That(receivedError).IsNull(); } - /// - /// Verifies that inner error after parent dispose is ignored. - /// + /// Verifies that inner error after parent dispose is ignored. /// A representing the asynchronous unit test. [Test] public async Task InnerErrorAfterDispose_IsIgnored() @@ -322,9 +288,9 @@ public async Task InnerErrorAfterDispose_IsIgnored() Exception? receivedError = null; var subscription = switchObs.Subscribe(new AnonymousObserver( - _ => { }, + static _ => { }, ex => receivedError = ex, - () => { })); + static () => { })); outerSubject.OnNext(innerSubject); subscription.Dispose(); @@ -335,9 +301,7 @@ public async Task InnerErrorAfterDispose_IsIgnored() await Assert.That(receivedError).IsNull(); } - /// - /// Verifies that inner OnCompleted does not propagate to the subscriber. - /// + /// Verifies that inner OnCompleted does not propagate to the subscriber. /// A representing the asynchronous unit test. [Test] public async Task InnerCompleted_DoesNotPropagateToSubscriber() @@ -349,9 +313,9 @@ public async Task InnerCompleted_DoesNotPropagateToSubscriber() var completed = false; var results = new List(); - switchObs.Subscribe(new AnonymousObserver( + _ = switchObs.Subscribe(new AnonymousObserver( results.Add, - _ => { }, + static _ => { }, () => completed = true)); outerSubject.OnNext(innerSubject); @@ -378,8 +342,8 @@ public async Task OnNext_AfterDispose_ViaManualObservable_IsIgnored() var subscription = switchObs.Subscribe(new AnonymousObserver( results.Add, - _ => { }, - () => { })); + static _ => { }, + static () => { })); // Dispose the subscription subscription.Dispose(); @@ -392,15 +356,12 @@ public async Task OnNext_AfterDispose_ViaManualObservable_IsIgnored() await Assert.That(results).IsEmpty(); } - /// - /// A simple observer that delegates to provided actions. - /// + /// A simple observer that delegates to provided actions. /// The type of elements observed. /// The action to invoke for each element. /// The action to invoke on error. /// The action to invoke on completion. - private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) - : IObserver + private sealed class AnonymousObserver(Action onNext, Action onError, Action onCompleted) : IObserver { /// public void OnCompleted() => onCompleted(); diff --git a/src/tests/ReactiveUI.Binding.Tests/ObservedChanged/ObservedChangedExtensionTests.cs b/src/tests/ReactiveUI.Binding.Tests/ObservedChanged/ObservedChangedExtensionTests.cs index f1de088..c1f6df6 100644 --- a/src/tests/ReactiveUI.Binding.Tests/ObservedChanged/ObservedChangedExtensionTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/ObservedChanged/ObservedChangedExtensionTests.cs @@ -9,19 +9,13 @@ namespace ReactiveUI.Binding.Tests.ObservedChanged; -/// -/// Tests for ObservedChangedMixin extension methods (Value, GetPropertyName, GetValue, GetValueOrDefault). -/// +/// Tests for ObservedChangedMixins extension methods (Value, GetPropertyName, GetValue, GetValueOrDefault). public class ObservedChangedExtensionTests { - /// - /// The expected number of emissions after the initial value plus one change. - /// + /// The expected number of emissions after the initial value plus one change. private const int ExpectedTwoEmissions = 2; - /// - /// Verifies that the Value extension converts observed changes to values. - /// + /// Verifies that the Value extension converts observed changes to values. /// A task representing the asynchronous test operation. [Test] public async Task Value_ConvertsObservedChangesToValues() @@ -44,9 +38,7 @@ public async Task Value_ConvertsObservedChangesToValues() await Assert.That(values[1]).IsEqualTo("End"); } - /// - /// Verifies that GetPropertyName returns the correct property path. - /// + /// Verifies that GetPropertyName returns the correct property path. /// A task representing the asynchronous test operation. [Test] public async Task GetPropertyName_ReturnsCorrectPath() @@ -59,9 +51,7 @@ public async Task GetPropertyName_ReturnsCorrectPath() await Assert.That(name).IsEqualTo("IsNotNullString"); } - /// - /// Verifies that GetPropertyName returns a dotted path for nested properties. - /// + /// Verifies that GetPropertyName returns a dotted path for nested properties. /// A task representing the asynchronous test operation. [Test] public async Task GetPropertyName_Nested_ReturnsDottedPath() @@ -74,9 +64,7 @@ public async Task GetPropertyName_Nested_ReturnsDottedPath() await Assert.That(name).IsEqualTo("Child.IsOnlyOneWord"); } - /// - /// Verifies that GetValue evaluates the expression chain to get the current value. - /// + /// Verifies that GetValue evaluates the expression chain to get the current value. /// A task representing the asynchronous test operation. [Test] public async Task GetValue_EvaluatesExpressionChain() @@ -92,9 +80,7 @@ public async Task GetValue_EvaluatesExpressionChain() await Assert.That(value).IsEqualTo("Evaluated"); } - /// - /// Verifies that GetValueOrDefault returns default when the chain contains a null. - /// + /// Verifies that GetValueOrDefault returns default when the chain contains a null. /// A task representing the asynchronous test operation. [Test] public async Task GetValueOrDefault_NullChain_ReturnsDefault() @@ -109,14 +95,12 @@ public async Task GetValueOrDefault_NullChain_ReturnsDefault() await Assert.That(value).IsNull(); } - /// - /// Resets and initializes the ReactiveUI binding infrastructure for testing. - /// + /// Resets and initializes the ReactiveUI binding infrastructure for testing. internal static void EnsureInitialized() { RxBindingBuilder.ResetForTesting(); var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - builder.WithCoreServices(); - builder.BuildApp(); + _ = builder.WithCoreServices(); + _ = builder.BuildApp(); } } diff --git a/src/tests/ReactiveUI.Binding.Tests/Reactive/ObserveOnObservableTests.cs b/src/tests/ReactiveUI.Binding.Tests/Reactive/ObserveOnObservableTests.cs index 2183ddc..c0f14bb 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Reactive/ObserveOnObservableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Reactive/ObserveOnObservableTests.cs @@ -8,39 +8,25 @@ namespace ReactiveUI.Binding.Tests.Reactive; -/// -/// Tests for the class which forwards notifications on a scheduler. -/// +/// Tests for the class which forwards notifications on a scheduler. public class ObserveOnObservableTests { - /// - /// The second value pushed through the source observable. - /// + /// The second value pushed through the source observable. private const int SecondValue = 2; - /// - /// The third value pushed through the source observable. - /// + /// The third value pushed through the source observable. private const int ThirdValue = 3; - /// - /// The index of the third received value. - /// + /// The index of the third received value. private const int ThirdIndex = 2; - /// - /// The expected number of forwarded notifications when three values are pushed. - /// + /// The expected number of forwarded notifications when three values are pushed. private const int ExpectedThreeCount = 3; - /// - /// The delay, in milliseconds, allowed for the scheduler to process notifications. - /// + /// The delay, in milliseconds, allowed for the scheduler to process notifications. private const int SchedulerProcessingDelayMs = 50; - /// - /// Verifies that notifications are forwarded to the observer. - /// + /// Verifies that notifications are forwarded to the observer. /// A task representing the asynchronous operation. [Test] public async Task Subscribe_ForwardsOnNextNotifications() @@ -49,9 +35,9 @@ public async Task Subscribe_ForwardsOnNextNotifications() var scheduler = new EventLoopScheduler(); var observable = new ObserveOnObservable(subject, scheduler); var received = new List(); - var completed = new TaskCompletionSource(); + var completed = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - observable.Subscribe( + _ = observable.Subscribe( received.Add, () => completed.SetResult(true)); @@ -69,9 +55,7 @@ public async Task Subscribe_ForwardsOnNextNotifications() await Assert.That(received[ThirdIndex]).IsEqualTo(ThirdValue); } - /// - /// Verifies that OnError is forwarded to the observer. - /// + /// Verifies that OnError is forwarded to the observer. /// A task representing the asynchronous operation. [Test] public async Task Subscribe_ForwardsOnErrorNotification() @@ -79,10 +63,10 @@ public async Task Subscribe_ForwardsOnErrorNotification() var subject = new Subject(); var scheduler = new EventLoopScheduler(); var observable = new ObserveOnObservable(subject, scheduler); - var errorReceived = new TaskCompletionSource(); + var errorReceived = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - observable.Subscribe( - _ => { }, + _ = observable.Subscribe( + static _ => { }, errorReceived.SetResult); var expected = new InvalidOperationException("test error"); @@ -94,9 +78,7 @@ public async Task Subscribe_ForwardsOnErrorNotification() await Assert.That(actual.Message).IsEqualTo("test error"); } - /// - /// Verifies that disposal stops notifications. - /// + /// Verifies that disposal stops notifications. /// A task representing the asynchronous operation. [Test] public async Task Subscribe_DisposalStopsNotifications() @@ -124,9 +106,7 @@ public async Task Subscribe_DisposalStopsNotifications() await Assert.That(received.Count).IsEqualTo(1); } - /// - /// Verifies that Subscribe throws ArgumentNullException when observer is null. - /// + /// Verifies that Subscribe throws ArgumentNullException when observer is null. [Test] public void Subscribe_NullObserver_ThrowsArgumentNullException() { @@ -134,28 +114,24 @@ public void Subscribe_NullObserver_ThrowsArgumentNullException() var scheduler = new EventLoopScheduler(); var observable = new ObserveOnObservable(subject, scheduler); - Assert.Throws(() => observable.Subscribe(null!)); + _ = Assert.Throws(() => observable.Subscribe(null!)); scheduler.Dispose(); } - /// - /// Verifies that constructor throws when source is null. - /// + /// Verifies that constructor throws when source is null. [Test] public void Constructor_NullSource_ThrowsArgumentNullException() { var scheduler = new EventLoopScheduler(); - Assert.Throws(() => _ = new ObserveOnObservable(null!, scheduler)); + _ = Assert.Throws(() => _ = new ObserveOnObservable(null!, scheduler)); scheduler.Dispose(); } - /// - /// Verifies that constructor throws when scheduler is null. - /// + /// Verifies that constructor throws when scheduler is null. [Test] public void Constructor_NullScheduler_ThrowsArgumentNullException() { var subject = new Subject(); - Assert.Throws(() => _ = new ObserveOnObservable(subject, null!)); + _ = Assert.Throws(() => _ = new ObserveOnObservable(subject, null!)); } } diff --git a/src/tests/ReactiveUI.Binding.Tests/Reactive/ReactiveSchedulerExtensionsTests.cs b/src/tests/ReactiveUI.Binding.Tests/Reactive/ReactiveSchedulerExtensionsTests.cs index a7e4f59..801c93d 100644 --- a/src/tests/ReactiveUI.Binding.Tests/Reactive/ReactiveSchedulerExtensionsTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/Reactive/ReactiveSchedulerExtensionsTests.cs @@ -14,16 +14,14 @@ namespace ReactiveUI.Binding.Tests.Reactive; /// public class ReactiveSchedulerExtensionsTests { - /// - /// Verifies that BindOneWay throws InvalidOperationException (no generated binding). - /// + /// Verifies that BindOneWay throws InvalidOperationException (no generated binding). [Test] public void BindOneWay_ThrowsInvalidOperationException() { var source = new TestModel(); var target = new TestModel(); - Assert.Throws(() => + _ = Assert.Throws(() => source.BindOneWay( target, s => s.Name, @@ -31,34 +29,30 @@ public void BindOneWay_ThrowsInvalidOperationException() (IScheduler?)null)); } - /// - /// Verifies that BindOneWay with conversion throws InvalidOperationException (no generated binding). - /// + /// Verifies that BindOneWay with conversion throws InvalidOperationException (no generated binding). [Test] public void BindOneWay_WithConversion_ThrowsInvalidOperationException() { var source = new TestModel(); var target = new TestModel(); - Assert.Throws(() => + _ = Assert.Throws(() => source.BindOneWay( target, s => s.Name, t => t.Name, - v => v, + static v => v, (IScheduler?)null)); } - /// - /// Verifies that BindTwoWay throws InvalidOperationException (no generated binding). - /// + /// Verifies that BindTwoWay throws InvalidOperationException (no generated binding). [Test] public void BindTwoWay_ThrowsInvalidOperationException() { var source = new TestModel(); var target = new TestModel(); - Assert.Throws(() => + _ = Assert.Throws(() => source.BindTwoWay( target, s => s.Name, @@ -66,47 +60,43 @@ public void BindTwoWay_ThrowsInvalidOperationException() (IScheduler?)null)); } - /// - /// Verifies that BindTwoWay with conversion throws InvalidOperationException (no generated binding). - /// + /// Verifies that BindTwoWay with conversion throws InvalidOperationException (no generated binding). [Test] public void BindTwoWay_WithConversion_ThrowsInvalidOperationException() { var source = new TestModel(); var target = new TestModel(); - Assert.Throws(() => + _ = Assert.Throws(() => source.BindTwoWay( target, s => s.Name, t => t.Name, - v => v, - v => v, + static v => v, + static v => v, (IScheduler?)null)); } - /// - /// A simple test model implementing . - /// + /// A simple test model implementing . private sealed class TestModel : INotifyPropertyChanged { /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// - [SuppressMessage( - "Major Code Smell", - "S3459:Unassigned members should be removed", - Justification = "Assigned indirectly by the two-way binding under test via the property selector; no literal assignment is visible to the analyzer.")] - public string? Name { get; set; } + /// Gets or sets the name. + public string? Name + { + get => field; + set + { + if (string.Equals(field, value, StringComparison.Ordinal)) + { + return; + } - /// - /// Raises the event for the specified property. - /// - /// The name of the property that changed. - public void OnPropertyChanged(string propertyName) => - PropertyChanged?.Invoke(this, new(propertyName)); + field = value; + PropertyChanged?.Invoke(this, new(nameof(Name))); + } + } } } diff --git a/src/tests/ReactiveUI.Binding.Tests/TestExecutors/BaseBindingBuilderTestExecutor.cs b/src/tests/ReactiveUI.Binding.Tests/TestExecutors/BaseBindingBuilderTestExecutor.cs index a7d07a8..fc812b3 100644 --- a/src/tests/ReactiveUI.Binding.Tests/TestExecutors/BaseBindingBuilderTestExecutor.cs +++ b/src/tests/ReactiveUI.Binding.Tests/TestExecutors/BaseBindingBuilderTestExecutor.cs @@ -21,7 +21,7 @@ namespace ReactiveUI.Binding.Tests.TestExecutors; /// Customizable builder configuration via virtual method. /// /// -public abstract class BaseBindingBuilderTestExecutor : ITestExecutor +public class BaseBindingBuilderTestExecutor : ITestExecutor { /// public virtual async ValueTask ExecuteTest(TestContext context, Func action) @@ -55,6 +55,6 @@ protected virtual void ConfigureAppBuilder(IReactiveUIBindingBuilder builder, Te ArgumentNullException.ThrowIfNull(builder); ArgumentNullException.ThrowIfNull(context); - builder.WithCoreServices(); + _ = builder.WithCoreServices(); } } diff --git a/src/tests/ReactiveUI.Binding.Tests/TestExecutors/BindingBuilderTestHelper.cs b/src/tests/ReactiveUI.Binding.Tests/TestExecutors/BindingBuilderTestHelper.cs index 778b744..1861908 100644 --- a/src/tests/ReactiveUI.Binding.Tests/TestExecutors/BindingBuilderTestHelper.cs +++ b/src/tests/ReactiveUI.Binding.Tests/TestExecutors/BindingBuilderTestHelper.cs @@ -14,10 +14,7 @@ namespace ReactiveUI.Binding.Tests.TestExecutors; /// public sealed class BindingBuilderTestHelper { - /// - /// Initializes the builder with custom configuration. - /// Resets builder state and configures using the provided action. - /// + /// Initializes the builder with custom configuration. Resets builder state and configures using the provided action. /// /// Action to configure the builder. Should call .WithCoreServices() at minimum. /// .BuildApp() is called automatically after the action. @@ -35,12 +32,10 @@ public static void Initialize(Action configureBuilder configureBuilder(builder); // Build the app with configured services - builder.BuildApp(); + _ = builder.BuildApp(); } - /// - /// Cleans up builder state and restores a clean environment for the next test. - /// + /// Cleans up builder state and restores a clean environment for the next test. public static void CleanUp() { // Reset generated view dispatch to avoid cross-test contamination @@ -50,7 +45,7 @@ public static void CleanUp() RxBindingBuilder.ResetForTesting(); // Rebuild with core services to ensure clean state for next test - RxBindingBuilder.CreateReactiveUIBindingBuilder() + _ = RxBindingBuilder.CreateReactiveUIBindingBuilder() .WithCoreServices() .BuildApp(); } diff --git a/src/tests/ReactiveUI.Binding.Tests/TestModels/HostTestFixture.cs b/src/tests/ReactiveUI.Binding.Tests/TestModels/HostTestFixture.cs index 79fc94c..644c8cd 100644 --- a/src/tests/ReactiveUI.Binding.Tests/TestModels/HostTestFixture.cs +++ b/src/tests/ReactiveUI.Binding.Tests/TestModels/HostTestFixture.cs @@ -13,88 +13,69 @@ namespace ReactiveUI.Binding.Tests.TestModels; /// public class HostTestFixture : INotifyPropertyChanged, INotifyPropertyChanging { - /// The backing field for . - private TestFixture? _child; - - /// The backing field for . - private int _someOtherParam; - - /// The backing field for . - private NonObservableTestFixture? _pocoChild; - /// public event PropertyChangedEventHandler? PropertyChanged; /// public event PropertyChangingEventHandler? PropertyChanging; - /// - /// Gets or sets the child test fixture. - /// + /// Gets or sets the child test fixture. public TestFixture? Child { - get => _child; + get => field; set { - if (ReferenceEquals(_child, value)) + if (ReferenceEquals(field, value)) { return; } OnPropertyChanging(); - _child = value; + field = value; OnPropertyChanged(); } } - /// - /// Gets or sets some other parameter. - /// + /// Gets or sets some other parameter. public int SomeOtherParam { - get => _someOtherParam; + get => field; set { - if (_someOtherParam == value) + if (field == value) { return; } OnPropertyChanging(); - _someOtherParam = value; + field = value; OnPropertyChanged(); } } - /// - /// Gets or sets the non-observable child. - /// + /// Gets or sets the non-observable child. public NonObservableTestFixture? PocoChild { - get => _pocoChild; + get => field; set { - if (ReferenceEquals(_pocoChild, value)) + if (ReferenceEquals(field, value)) { return; } OnPropertyChanging(); - _pocoChild = value; + field = value; OnPropertyChanged(); } } - /// - /// Raises the PropertyChanging event. - /// + /// Raises the PropertyChanging event. /// The property name. protected void OnPropertyChanging([CallerMemberName] string? propertyName = null) => PropertyChanging?.Invoke(this, new(propertyName)); - /// - /// Raises the PropertyChanged event. - /// + /// Raises the PropertyChanged event. /// The property name. protected void OnPropertyChanged([CallerMemberName] string? propertyName = null) => PropertyChanged?.Invoke(this, new(propertyName)); diff --git a/src/tests/ReactiveUI.Binding.Tests/TestModels/ManualObservable.cs b/src/tests/ReactiveUI.Binding.Tests/TestModels/ManualObservable.cs index 3a7432f..296697d 100644 --- a/src/tests/ReactiveUI.Binding.Tests/TestModels/ManualObservable.cs +++ b/src/tests/ReactiveUI.Binding.Tests/TestModels/ManualObservable.cs @@ -12,10 +12,8 @@ namespace ReactiveUI.Binding.Tests.TestModels; /// The element type. internal sealed class ManualObservable : IObservable { - /// - /// Gets the observer that was passed to Subscribe. - /// - public IObserver? Observer { get; private set; } + /// Gets the observer that was passed to Subscribe. + internal IObserver? Observer { get; private set; } /// public IDisposable Subscribe(IObserver observer) @@ -24,9 +22,7 @@ public IDisposable Subscribe(IObserver observer) return new NoOpDisposable(); } - /// - /// A disposable that performs no action on dispose. - /// + /// A disposable that performs no action on dispose. private sealed class NoOpDisposable : IDisposable { /// diff --git a/src/tests/ReactiveUI.Binding.Tests/TestModels/NonObservableTestFixture.cs b/src/tests/ReactiveUI.Binding.Tests/TestModels/NonObservableTestFixture.cs index b85236d..f347ad1 100644 --- a/src/tests/ReactiveUI.Binding.Tests/TestModels/NonObservableTestFixture.cs +++ b/src/tests/ReactiveUI.Binding.Tests/TestModels/NonObservableTestFixture.cs @@ -4,13 +4,9 @@ namespace ReactiveUI.Binding.Tests.TestModels; -/// -/// A POCO with no change notification support, used to test fallback behavior. -/// +/// A POCO with no change notification support, used to test fallback behavior. public class NonObservableTestFixture { - /// - /// Gets or sets a property that cannot be observed for changes. - /// + /// Gets or sets a property that cannot be observed for changes. public string NotListeningProperty { get; set; } = string.Empty; } diff --git a/src/tests/ReactiveUI.Binding.Tests/TestModels/NonReactiveINotifyPropertyChangedObject.cs b/src/tests/ReactiveUI.Binding.Tests/TestModels/NonReactiveINotifyPropertyChangedObject.cs index f20169f..dab2190 100644 --- a/src/tests/ReactiveUI.Binding.Tests/TestModels/NonReactiveINotifyPropertyChangedObject.cs +++ b/src/tests/ReactiveUI.Binding.Tests/TestModels/NonReactiveINotifyPropertyChangedObject.cs @@ -13,35 +13,26 @@ namespace ReactiveUI.Binding.Tests.TestModels; /// public class NonReactiveINotifyPropertyChangedObject : INotifyPropertyChanged { - /// - /// The backing field for . - /// - private string _inpcProperty = string.Empty; - /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the INPC property. - /// + /// Gets or sets the INPC property. public string InpcProperty { - get => _inpcProperty; + get => field; set { - if (_inpcProperty == value) + if (field == value) { return; } - _inpcProperty = value; + field = value; OnPropertyChanged(); } - } + } = string.Empty; - /// - /// Raises the PropertyChanged event. - /// + /// Raises the PropertyChanged event. /// The property name. protected void OnPropertyChanged([CallerMemberName] string? propertyName = null) => PropertyChanged?.Invoke(this, new(propertyName)); diff --git a/src/tests/ReactiveUI.Binding.Tests/TestModels/ObjChain1.cs b/src/tests/ReactiveUI.Binding.Tests/TestModels/ObjChain1.cs index 8ac6c5b..b27648b 100644 --- a/src/tests/ReactiveUI.Binding.Tests/TestModels/ObjChain1.cs +++ b/src/tests/ReactiveUI.Binding.Tests/TestModels/ObjChain1.cs @@ -7,40 +7,29 @@ namespace ReactiveUI.Binding.Tests.TestModels; -/// -/// Top-level object in a 4-level deep chain: ObjChain1 → ObjChain2 → ObjChain3 → HostTestFixture. -/// +/// Top-level object in a 4-level deep chain: ObjChain1 → ObjChain2 → ObjChain3 → HostTestFixture. public class ObjChain1 : INotifyPropertyChanged { - /// - /// The backer for Chain2. - /// - private ObjChain2? _chain2; - /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the next link in the chain. - /// + /// Gets or sets the next link in the chain. public ObjChain2? Chain2 { - get => _chain2; + get => field; set { - if (ReferenceEquals(_chain2, value)) + if (ReferenceEquals(field, value)) { return; } - _chain2 = value; + field = value; OnPropertyChanged(); } } - /// - /// Raises the PropertyChanged event. - /// + /// Raises the PropertyChanged event. /// The property name. protected void OnPropertyChanged([CallerMemberName] string? propertyName = null) => PropertyChanged?.Invoke(this, new(propertyName)); diff --git a/src/tests/ReactiveUI.Binding.Tests/TestModels/ObjChain2.cs b/src/tests/ReactiveUI.Binding.Tests/TestModels/ObjChain2.cs index c810862..fedafb2 100644 --- a/src/tests/ReactiveUI.Binding.Tests/TestModels/ObjChain2.cs +++ b/src/tests/ReactiveUI.Binding.Tests/TestModels/ObjChain2.cs @@ -7,40 +7,29 @@ namespace ReactiveUI.Binding.Tests.TestModels; -/// -/// Second-level object in a 4-level deep chain: ObjChain1 → ObjChain2 → ObjChain3 → HostTestFixture. -/// +/// Second-level object in a 4-level deep chain: ObjChain1 → ObjChain2 → ObjChain3 → HostTestFixture. public class ObjChain2 : INotifyPropertyChanged { - /// - /// The backer for Chain3. - /// - private ObjChain3? _chain3; - /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the next link in the chain. - /// + /// Gets or sets the next link in the chain. public ObjChain3? Chain3 { - get => _chain3; + get => field; set { - if (ReferenceEquals(_chain3, value)) + if (ReferenceEquals(field, value)) { return; } - _chain3 = value; + field = value; OnPropertyChanged(); } } - /// - /// Raises the PropertyChanged event. - /// + /// Raises the PropertyChanged event. /// The property name. protected void OnPropertyChanged([CallerMemberName] string? propertyName = null) => PropertyChanged?.Invoke(this, new(propertyName)); diff --git a/src/tests/ReactiveUI.Binding.Tests/TestModels/ObjChain3.cs b/src/tests/ReactiveUI.Binding.Tests/TestModels/ObjChain3.cs index 960518f..c8297ed 100644 --- a/src/tests/ReactiveUI.Binding.Tests/TestModels/ObjChain3.cs +++ b/src/tests/ReactiveUI.Binding.Tests/TestModels/ObjChain3.cs @@ -7,40 +7,29 @@ namespace ReactiveUI.Binding.Tests.TestModels; -/// -/// Third-level object in a 4-level deep chain: ObjChain1 → ObjChain2 → ObjChain3 → HostTestFixture. -/// +/// Third-level object in a 4-level deep chain: ObjChain1 → ObjChain2 → ObjChain3 → HostTestFixture. public class ObjChain3 : INotifyPropertyChanged { - /// - /// The backer for Host. - /// - private HostTestFixture? _host; - /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the host test fixture at the end of the chain. - /// + /// Gets or sets the host test fixture at the end of the chain. public HostTestFixture? Host { - get => _host; + get => field; set { - if (ReferenceEquals(_host, value)) + if (ReferenceEquals(field, value)) { return; } - _host = value; + field = value; OnPropertyChanged(); } } - /// - /// Raises the PropertyChanged event. - /// + /// Raises the PropertyChanged event. /// The property name. protected void OnPropertyChanged([CallerMemberName] string? propertyName = null) => PropertyChanged?.Invoke(this, new(propertyName)); diff --git a/src/tests/ReactiveUI.Binding.Tests/TestModels/OwnerClass.cs b/src/tests/ReactiveUI.Binding.Tests/TestModels/OwnerClass.cs index a453025..58b2eae 100644 --- a/src/tests/ReactiveUI.Binding.Tests/TestModels/OwnerClass.cs +++ b/src/tests/ReactiveUI.Binding.Tests/TestModels/OwnerClass.cs @@ -7,40 +7,29 @@ namespace ReactiveUI.Binding.Tests.TestModels; -/// -/// A simple observable class with a Name property. -/// +/// A simple observable class with a Name property. public class OwnerClass : INotifyPropertyChanged { - /// - /// The backer for Name. - /// - private string _name = string.Empty; - /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { - get => _name; + get => field; set { - if (_name == value) + if (field == value) { return; } - _name = value; + field = value; OnPropertyChanged(); } - } + } = string.Empty; - /// - /// Raises the PropertyChanged event. - /// + /// Raises the PropertyChanged event. /// The property name. protected void OnPropertyChanged([CallerMemberName] string? propertyName = null) => PropertyChanged?.Invoke(this, new(propertyName)); diff --git a/src/tests/ReactiveUI.Binding.Tests/TestModels/PocoModel.cs b/src/tests/ReactiveUI.Binding.Tests/TestModels/PocoModel.cs index 9c4910d..9f009e9 100644 --- a/src/tests/ReactiveUI.Binding.Tests/TestModels/PocoModel.cs +++ b/src/tests/ReactiveUI.Binding.Tests/TestModels/PocoModel.cs @@ -4,13 +4,9 @@ namespace ReactiveUI.Binding.Tests.TestModels; -/// -/// A plain old CLR object with no change notification support. -/// +/// A plain old CLR object with no change notification support. public class PocoModel { - /// - /// Gets or sets the value. - /// + /// Gets or sets the value. public string Value { get; set; } = string.Empty; } diff --git a/src/tests/ReactiveUI.Binding.Tests/TestModels/StubBindingTypeConverter.cs b/src/tests/ReactiveUI.Binding.Tests/TestModels/StubBindingTypeConverter.cs index 0d1ff18..1b8d4eb 100644 --- a/src/tests/ReactiveUI.Binding.Tests/TestModels/StubBindingTypeConverter.cs +++ b/src/tests/ReactiveUI.Binding.Tests/TestModels/StubBindingTypeConverter.cs @@ -4,24 +4,16 @@ namespace ReactiveUI.Binding.Tests.TestModels; -/// -/// A stub implementation of for testing. -/// +/// A stub implementation of for testing. public class StubBindingTypeConverter : IBindingTypeConverter { - /// - /// Affinity returned by this stub converter to indicate it can handle the conversion. - /// + /// Affinity returned by this stub converter to indicate it can handle the conversion. private const int StubAffinity = 10; - /// - /// The conversion logic. - /// + /// The conversion logic. private readonly Func _tryConvert; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The source type. /// The target type. /// The conversion logic. diff --git a/src/tests/ReactiveUI.Binding.Tests/TestModels/StubFallbackConverter.cs b/src/tests/ReactiveUI.Binding.Tests/TestModels/StubFallbackConverter.cs index 9c1f461..49353e2 100644 --- a/src/tests/ReactiveUI.Binding.Tests/TestModels/StubFallbackConverter.cs +++ b/src/tests/ReactiveUI.Binding.Tests/TestModels/StubFallbackConverter.cs @@ -4,24 +4,16 @@ namespace ReactiveUI.Binding.Tests.TestModels; -/// -/// A stub implementation of for testing. -/// +/// A stub implementation of for testing. public class StubFallbackConverter : IBindingFallbackConverter { - /// - /// The fixed affinity score returned by this stub converter. - /// + /// The fixed affinity score returned by this stub converter. private const int StubAffinity = 5; - /// - /// The conversion logic. - /// + /// The conversion logic. private readonly Func _tryConvert; - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The conversion logic. public StubFallbackConverter(Func tryConvert) => _tryConvert = tryConvert; diff --git a/src/tests/ReactiveUI.Binding.Tests/TestModels/StubSetMethodBindingConverter.cs b/src/tests/ReactiveUI.Binding.Tests/TestModels/StubSetMethodBindingConverter.cs index f7d4114..21d37ef 100644 --- a/src/tests/ReactiveUI.Binding.Tests/TestModels/StubSetMethodBindingConverter.cs +++ b/src/tests/ReactiveUI.Binding.Tests/TestModels/StubSetMethodBindingConverter.cs @@ -4,33 +4,22 @@ namespace ReactiveUI.Binding.Tests.TestModels; -/// -/// A stub implementation of for testing. -/// +/// A stub implementation of for testing. public class StubSetMethodBindingConverter : ISetMethodBindingConverter { - /// - /// The default affinity score used when none is supplied. - /// + /// The default affinity score used when none is supplied. private const int DefaultAffinity = 10; - /// - /// The affinity score to return. - /// + /// The affinity score to return. private readonly int _affinity; - /// - /// Initializes a new instance of the class - /// using the default affinity score. - /// + /// Initializes a new instance of the class using the default affinity score. public StubSetMethodBindingConverter() : this(DefaultAffinity) { } - /// - /// Initializes a new instance of the class. - /// + /// Initializes a new instance of the class. /// The affinity score to return. public StubSetMethodBindingConverter(int affinity) => _affinity = affinity; diff --git a/src/tests/ReactiveUI.Binding.Tests/TestModels/TestAddress.cs b/src/tests/ReactiveUI.Binding.Tests/TestModels/TestAddress.cs index ffd7c04..9fdd723 100644 --- a/src/tests/ReactiveUI.Binding.Tests/TestModels/TestAddress.cs +++ b/src/tests/ReactiveUI.Binding.Tests/TestModels/TestAddress.cs @@ -6,34 +6,25 @@ namespace ReactiveUI.Binding.Tests.TestModels; -/// -/// A nested test model for testing expression chains. -/// +/// A nested test model for testing expression chains. public class TestAddress : INotifyPropertyChanged { - /// - /// The backer for City. - /// - private string _city = string.Empty; - /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the city. - /// + /// Gets or sets the city. public string City { - get => _city; + get => field; set { - if (_city == value) + if (field == value) { return; } - _city = value; + field = value; PropertyChanged?.Invoke(this, new(nameof(City))); } - } + } = string.Empty; } diff --git a/src/tests/ReactiveUI.Binding.Tests/TestModels/TestFixture.cs b/src/tests/ReactiveUI.Binding.Tests/TestModels/TestFixture.cs index 7111839..3d8697d 100644 --- a/src/tests/ReactiveUI.Binding.Tests/TestModels/TestFixture.cs +++ b/src/tests/ReactiveUI.Binding.Tests/TestModels/TestFixture.cs @@ -13,132 +13,103 @@ namespace ReactiveUI.Binding.Tests.TestModels; /// public class TestFixture : INotifyPropertyChanged, INotifyPropertyChanging { - /// The backing field for . - private string _isNotNullString = "Foo"; - - /// The backing field for . - private string _isOnlyOneWord = "Baz"; - - /// The backing field for . - private string _pocoProperty = string.Empty; - - /// The backing field for . - private int? _nullableInt; - - /// The backing field for . - private string _usesExprRaiseSet = string.Empty; - /// public event PropertyChangedEventHandler? PropertyChanged; /// public event PropertyChangingEventHandler? PropertyChanging; - /// - /// Gets or sets a non-null string property. - /// + /// Gets or sets a non-null string property. public string IsNotNullString { - get => _isNotNullString; + get => field; set { - if (_isNotNullString == value) + if (field == value) { return; } OnPropertyChanging(); - _isNotNullString = value; + field = value; OnPropertyChanged(); } - } + } = "Foo"; - /// - /// Gets or sets a single-word string property. - /// + /// Gets or sets a single-word string property. public string IsOnlyOneWord { - get => _isOnlyOneWord; + get => field; set { - if (_isOnlyOneWord == value) + if (field == value) { return; } OnPropertyChanging(); - _isOnlyOneWord = value; + field = value; OnPropertyChanged(); } - } + } = "Baz"; - /// - /// Gets or sets a property without change notification behavior. - /// + /// Gets or sets a property without change notification behavior. public string PocoProperty { - get => _pocoProperty; + get => field; set { - if (_pocoProperty == value) + if (field == value) { return; } OnPropertyChanging(); - _pocoProperty = value; + field = value; OnPropertyChanged(); } - } + } = string.Empty; - /// - /// Gets or sets a nullable integer property. - /// + /// Gets or sets a nullable integer property. public int? NullableInt { - get => _nullableInt; + get => field; set { - if (_nullableInt == value) + if (field == value) { return; } OnPropertyChanging(); - _nullableInt = value; + field = value; OnPropertyChanged(); } } - /// - /// Gets or sets a property that uses expression-based raise and set. - /// + /// Gets or sets a property that uses expression-based raise and set. public string UsesExprRaiseSet { - get => _usesExprRaiseSet; + get => field; set { - if (_usesExprRaiseSet == value) + if (field == value) { return; } OnPropertyChanging(); - _usesExprRaiseSet = value; + field = value; OnPropertyChanged(); } - } + } = string.Empty; - /// - /// Raises the PropertyChanging event. - /// + /// Raises the PropertyChanging event. /// The property name. protected void OnPropertyChanging([CallerMemberName] string? propertyName = null) => PropertyChanging?.Invoke(this, new(propertyName)); - /// - /// Raises the PropertyChanged event. - /// + /// Raises the PropertyChanged event. /// The property name. protected void OnPropertyChanged([CallerMemberName] string? propertyName = null) => PropertyChanged?.Invoke(this, new(propertyName)); diff --git a/src/tests/ReactiveUI.Binding.Tests/TestModels/TestViewModel.cs b/src/tests/ReactiveUI.Binding.Tests/TestModels/TestViewModel.cs index d68dca5..07d18c5 100644 --- a/src/tests/ReactiveUI.Binding.Tests/TestModels/TestViewModel.cs +++ b/src/tests/ReactiveUI.Binding.Tests/TestModels/TestViewModel.cs @@ -7,99 +7,72 @@ namespace ReactiveUI.Binding.Tests.TestModels; -/// -/// A test view model implementing INotifyPropertyChanged and INotifyPropertyChanging. -/// +/// A test view model implementing INotifyPropertyChanged and INotifyPropertyChanging. public class TestViewModel : INotifyPropertyChanged, INotifyPropertyChanging { - /// - /// The backer for Name. - /// - private string _name = string.Empty; - - /// - /// The backer for Age. - /// - private int _age; - - /// - /// The backer for Address. - /// - private TestAddress? _address; - /// public event PropertyChangedEventHandler? PropertyChanged; /// public event PropertyChangingEventHandler? PropertyChanging; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { - get => _name; + get => field; set { - if (_name == value) + if (field == value) { return; } OnPropertyChanging(); - _name = value; + field = value; OnPropertyChanged(); } - } + } = string.Empty; - /// - /// Gets or sets the age. - /// + /// Gets or sets the age. public int Age { - get => _age; + get => field; set { - if (_age == value) + if (field == value) { return; } OnPropertyChanging(); - _age = value; + field = value; OnPropertyChanged(); } } - /// - /// Gets or sets the address. - /// + /// Gets or sets the address. public TestAddress? Address { - get => _address; + get => field; set { - if (ReferenceEquals(_address, value)) + if (ReferenceEquals(field, value)) { return; } OnPropertyChanging(); - _address = value; + field = value; OnPropertyChanged(); } } - /// - /// Raises the PropertyChanging event. - /// + /// Raises the PropertyChanging event. /// The property name. protected void OnPropertyChanging([CallerMemberName] string? propertyName = null) => PropertyChanging?.Invoke(this, new(propertyName)); - /// - /// Raises the PropertyChanged event. - /// + /// Raises the PropertyChanged event. /// The property name. protected void OnPropertyChanged([CallerMemberName] string? propertyName = null) => PropertyChanged?.Invoke(this, new(propertyName)); diff --git a/src/tests/ReactiveUI.Binding.Tests/TestModels/TestWhenAnyObsViewModel.cs b/src/tests/ReactiveUI.Binding.Tests/TestModels/TestWhenAnyObsViewModel.cs index cdf59bb..3916051 100644 --- a/src/tests/ReactiveUI.Binding.Tests/TestModels/TestWhenAnyObsViewModel.cs +++ b/src/tests/ReactiveUI.Binding.Tests/TestModels/TestWhenAnyObsViewModel.cs @@ -7,101 +7,77 @@ namespace ReactiveUI.Binding.Tests.TestModels; -/// -/// A view model for testing WhenAnyObservable with observable properties. -/// +/// A view model for testing WhenAnyObservable with observable properties. public class TestWhenAnyObsViewModel : INotifyPropertyChanged { - /// The backing field for . - private IObservable? _command1; - - /// The backing field for . - private IObservable? _command2; - - /// The backing field for . - private IObservable? _command3; - - /// The backing field for . - private IObservable? _changes; - /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the first command observable. - /// + /// Gets or sets the first command observable. public IObservable? Command1 { - get => _command1; + get => field; set { - if (ReferenceEquals(_command1, value)) + if (ReferenceEquals(field, value)) { return; } - _command1 = value; + field = value; OnPropertyChanged(); } } - /// - /// Gets or sets the second command observable. - /// + /// Gets or sets the second command observable. public IObservable? Command2 { - get => _command2; + get => field; set { - if (ReferenceEquals(_command2, value)) + if (ReferenceEquals(field, value)) { return; } - _command2 = value; + field = value; OnPropertyChanged(); } } - /// - /// Gets or sets the third command observable. - /// + /// Gets or sets the third command observable. public IObservable? Command3 { - get => _command3; + get => field; set { - if (ReferenceEquals(_command3, value)) + if (ReferenceEquals(field, value)) { return; } - _command3 = value; + field = value; OnPropertyChanged(); } } - /// - /// Gets or sets the changes observable. - /// + /// Gets or sets the changes observable. public IObservable? Changes { - get => _changes; + get => field; set { - if (ReferenceEquals(_changes, value)) + if (ReferenceEquals(field, value)) { return; } - _changes = value; + field = value; OnPropertyChanged(); } } - /// - /// Raises the PropertyChanged event. - /// + /// Raises the PropertyChanged event. /// The property name. protected void OnPropertyChanged([CallerMemberName] string? propertyName = null) => PropertyChanged?.Invoke(this, new(propertyName)); diff --git a/src/tests/ReactiveUI.Binding.Tests/TestModels/WhenAnyTestFixture.cs b/src/tests/ReactiveUI.Binding.Tests/TestModels/WhenAnyTestFixture.cs index bd23714..7dff382 100644 --- a/src/tests/ReactiveUI.Binding.Tests/TestModels/WhenAnyTestFixture.cs +++ b/src/tests/ReactiveUI.Binding.Tests/TestModels/WhenAnyTestFixture.cs @@ -7,245 +7,205 @@ namespace ReactiveUI.Binding.Tests.TestModels; -/// -/// A test fixture with 12 value properties for multi-property WhenAnyValue testing. -/// +/// A test fixture with 12 value properties for multi-property WhenAnyValue testing. public class WhenAnyTestFixture : INotifyPropertyChanged { - /// The backing field for . - private string _value1 = string.Empty; - - /// The backing field for . - private string _value2 = string.Empty; - - /// The backing field for . - private string _value3 = string.Empty; - - /// The backing field for . - private string _value4 = string.Empty; - - /// The backing field for . - private string _value5 = string.Empty; - - /// The backing field for . - private string _value6 = string.Empty; - - /// The backing field for . - private string _value7 = string.Empty; - - /// The backing field for . - private string _value8 = string.Empty; - - /// The backing field for . - private string _value9 = string.Empty; - - /// The backing field for . - private string _value10 = string.Empty; - - /// The backing field for . - private string _value11 = string.Empty; - - /// The backing field for . - private string _value12 = string.Empty; - /// public event PropertyChangedEventHandler? PropertyChanged; /// Gets or sets value 1. public string Value1 { - get => _value1; + get => field; set { - if (_value1 == value) + if (field == value) { return; } - _value1 = value; + field = value; OnPropertyChanged(); } - } + } = string.Empty; /// Gets or sets value 2. public string Value2 { - get => _value2; + get => field; set { - if (_value2 == value) + if (field == value) { return; } - _value2 = value; + field = value; OnPropertyChanged(); } - } + } = string.Empty; /// Gets or sets value 3. public string Value3 { - get => _value3; + get => field; set { - if (_value3 == value) + if (field == value) { return; } - _value3 = value; + field = value; OnPropertyChanged(); } - } + } = string.Empty; /// Gets or sets value 4. public string Value4 { - get => _value4; + get => field; set { - if (_value4 == value) + if (field == value) { return; } - _value4 = value; + field = value; OnPropertyChanged(); } - } + } = string.Empty; /// Gets or sets value 5. public string Value5 { - get => _value5; + get => field; set { - if (_value5 == value) + if (field == value) { return; } - _value5 = value; + field = value; OnPropertyChanged(); } - } + } = string.Empty; /// Gets or sets value 6. public string Value6 { - get => _value6; + get => field; set { - if (_value6 == value) + if (field == value) { return; } - _value6 = value; + field = value; OnPropertyChanged(); } - } + } = string.Empty; /// Gets or sets value 7. public string Value7 { - get => _value7; + get => field; set { - if (_value7 == value) + if (field == value) { return; } - _value7 = value; + field = value; OnPropertyChanged(); } - } + } = string.Empty; /// Gets or sets value 8. public string Value8 { - get => _value8; + get => field; set { - if (_value8 == value) + if (field == value) { return; } - _value8 = value; + field = value; OnPropertyChanged(); } - } + } = string.Empty; /// Gets or sets value 9. public string Value9 { - get => _value9; + get => field; set { - if (_value9 == value) + if (field == value) { return; } - _value9 = value; + field = value; OnPropertyChanged(); } - } + } = string.Empty; /// Gets or sets value 10. public string Value10 { - get => _value10; + get => field; set { - if (_value10 == value) + if (field == value) { return; } - _value10 = value; + field = value; OnPropertyChanged(); } - } + } = string.Empty; /// Gets or sets value 11. public string Value11 { - get => _value11; + get => field; set { - if (_value11 == value) + if (field == value) { return; } - _value11 = value; + field = value; OnPropertyChanged(); } - } + } = string.Empty; /// Gets or sets value 12. public string Value12 { - get => _value12; + get => field; set { - if (_value12 == value) + if (field == value) { return; } - _value12 = value; + field = value; OnPropertyChanged(); } - } + } = string.Empty; - /// - /// Raises the PropertyChanged event. - /// + /// Raises the PropertyChanged event. /// The property name. protected void OnPropertyChanged([CallerMemberName] string? propertyName = null) => PropertyChanged?.Invoke(this, new(propertyName)); diff --git a/src/tests/ReactiveUI.Binding.Tests/View/DefaultViewLocatorTests.cs b/src/tests/ReactiveUI.Binding.Tests/View/DefaultViewLocatorTests.cs index 97e6ab9..d072e3d 100644 --- a/src/tests/ReactiveUI.Binding.Tests/View/DefaultViewLocatorTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/View/DefaultViewLocatorTests.cs @@ -7,16 +7,12 @@ namespace ReactiveUI.Binding.Tests.View; -/// -/// Tests for the class. -/// +/// Tests for the class. [NotInParallel] [TestExecutor] public class DefaultViewLocatorTests { - /// - /// Verifies that ResolveView returns null when the view model is null. - /// + /// Verifies that ResolveView returns null when the view model is null. /// A task representing the asynchronous test operation. [Test] public async Task ResolveView_NullViewModel_ReturnsNull() @@ -28,9 +24,7 @@ public async Task ResolveView_NullViewModel_ReturnsNull() await Assert.That(result).IsNull(); } - /// - /// Verifies that the generic ResolveView returns null when the view model is null. - /// + /// Verifies that the generic ResolveView returns null when the view model is null. /// A task representing the asynchronous test operation. [Test] public async Task ResolveViewGeneric_NullViewModel_ReturnsNull() @@ -42,9 +36,7 @@ public async Task ResolveViewGeneric_NullViewModel_ReturnsNull() await Assert.That(result).IsNull(); } - /// - /// Verifies that Map registers a view and ResolveView resolves it. - /// + /// Verifies that Map registers a view and ResolveView resolves it. /// A task representing the asynchronous test operation. [Test] public async Task Map_ThenResolve_ReturnsView() @@ -58,9 +50,7 @@ public async Task Map_ThenResolve_ReturnsView() await Assert.That(result).IsTypeOf(); } - /// - /// Verifies that Map with a factory creates views using the factory. - /// + /// Verifies that Map with a factory creates views using the factory. /// A task representing the asynchronous test operation. [Test] public async Task MapWithFactory_ThenResolve_UsesFactory() @@ -79,9 +69,7 @@ public async Task MapWithFactory_ThenResolve_UsesFactory() await Assert.That(result).IsNotNull(); } - /// - /// Verifies that the generic ResolveView resolves from explicit mappings. - /// + /// Verifies that the generic ResolveView resolves from explicit mappings. /// A task representing the asynchronous test operation. [Test] public async Task ResolveViewGeneric_WithMapping_ReturnsView() @@ -96,9 +84,7 @@ public async Task ResolveViewGeneric_WithMapping_ReturnsView() await Assert.That(result!.ViewModel).IsEqualTo(vm); } - /// - /// Verifies that Unmap removes a mapping and subsequent resolves return null. - /// + /// Verifies that Unmap removes a mapping and subsequent resolves return null. /// A task representing the asynchronous test operation. [Test] public async Task Unmap_RemovesMapping() @@ -113,9 +99,7 @@ public async Task Unmap_RemovesMapping() await Assert.That(result).IsNull(); } - /// - /// Verifies that Unmap returns false when no mapping exists. - /// + /// Verifies that Unmap returns false when no mapping exists. /// A task representing the asynchronous test operation. [Test] public async Task Unmap_NoMapping_ReturnsFalse() @@ -127,9 +111,7 @@ public async Task Unmap_NoMapping_ReturnsFalse() await Assert.That(removed).IsFalse(); } - /// - /// Verifies that contracts provide independent namespaces for mappings. - /// + /// Verifies that contracts provide independent namespaces for mappings. /// A task representing the asynchronous test operation. [Test] public async Task Map_WithContract_ResolvesByContract() @@ -144,9 +126,7 @@ public async Task Map_WithContract_ResolvesByContract() await Assert.That(withoutContract).IsNull(); } - /// - /// Verifies that ResolveView sets the ViewModel property on the resolved view. - /// + /// Verifies that ResolveView sets the ViewModel property on the resolved view. /// A task representing the asynchronous test operation. [Test] public async Task ResolveView_SetsViewModelOnView() @@ -161,9 +141,7 @@ public async Task ResolveView_SetsViewModelOnView() await Assert.That(view!.ViewModel).IsEqualTo(vm); } - /// - /// Verifies that the generated dispatch function is called when set. - /// + /// Verifies that the generated dispatch function is called when set. /// A task representing the asynchronous test operation. [Test] public async Task SetGeneratedViewDispatch_IsUsedByResolve() @@ -183,16 +161,14 @@ public async Task SetGeneratedViewDispatch_IsUsedByResolve() await Assert.That(result).IsNotNull(); } - /// - /// Verifies that generated dispatch takes priority over explicit mappings. - /// + /// Verifies that generated dispatch takes priority over explicit mappings. /// A task representing the asynchronous test operation. [Test] public async Task GeneratedDispatch_TakesPriorityOverMappings() { var locator = new DefaultViewLocator(); var generatedView = new TestView(); - locator.Map(() => new TestView()); + locator.Map(static () => new TestView()); DefaultViewLocator.SetGeneratedViewDispatch((_, _) => generatedView); @@ -201,9 +177,7 @@ public async Task GeneratedDispatch_TakesPriorityOverMappings() await Assert.That(result).IsEqualTo(generatedView); } - /// - /// Verifies that when generated dispatch returns null, mappings are used as fallback. - /// + /// Verifies that when generated dispatch returns null, mappings are used as fallback. /// A task representing the asynchronous test operation. [Test] public async Task GeneratedDispatch_ReturnsNull_FallsBackToMappings() @@ -211,7 +185,7 @@ public async Task GeneratedDispatch_ReturnsNull_FallsBackToMappings() var locator = new DefaultViewLocator(); locator.Map(); - DefaultViewLocator.SetGeneratedViewDispatch((_, _) => null); + DefaultViewLocator.SetGeneratedViewDispatch(static (_, _) => null); var result = locator.ResolveView(new TestViewModel()); @@ -219,9 +193,7 @@ public async Task GeneratedDispatch_ReturnsNull_FallsBackToMappings() await Assert.That(result).IsTypeOf(); } - /// - /// Verifies that the generic ResolveView uses the generated dispatch. - /// + /// Verifies that the generic ResolveView uses the generated dispatch. /// A task representing the asynchronous test operation. [Test] public async Task ResolveViewGeneric_UsesGeneratedDispatch() @@ -236,9 +208,7 @@ public async Task ResolveViewGeneric_UsesGeneratedDispatch() await Assert.That(result).IsEqualTo(generatedView); } - /// - /// Verifies that null contract is normalized to empty string. - /// + /// Verifies that null contract is normalized to empty string. /// A task representing the asynchronous test operation. [Test] public async Task ResolveView_NullContract_NormalizedToEmpty() @@ -253,21 +223,17 @@ public async Task ResolveView_NullContract_NormalizedToEmpty() await Assert.That(withEmpty).IsNotNull(); } - /// - /// Verifies that SetGeneratedViewDispatch throws on null argument. - /// + /// Verifies that SetGeneratedViewDispatch throws on null argument. /// A task representing the asynchronous test operation. [Test] public async Task SetGeneratedViewDispatch_NullThrows() { - var action = () => DefaultViewLocator.SetGeneratedViewDispatch(null!); + var action = static () => DefaultViewLocator.SetGeneratedViewDispatch(null!); await Assert.That(action).ThrowsException(); } - /// - /// Verifies that Map with factory throws on null factory. - /// + /// Verifies that Map with factory throws on null factory. /// A task representing the asynchronous test operation. [Test] public async Task MapWithFactory_NullFactory_Throws() @@ -278,9 +244,7 @@ public async Task MapWithFactory_NullFactory_Throws() await Assert.That(action).ThrowsException(); } - /// - /// Verifies that generic ResolveView falls back to service locator when no dispatch or mapping exists. - /// + /// Verifies that generic ResolveView falls back to service locator when no dispatch or mapping exists. /// A task representing the asynchronous test operation. [Test] public async Task ResolveViewGeneric_ServiceLocatorFallback() @@ -289,7 +253,7 @@ public async Task ResolveViewGeneric_ServiceLocatorFallback() var vm = new TestViewModel(); // Register an IViewFor in the service locator - AppLocator.CurrentMutable.Register>(() => new TestView()); + AppLocator.CurrentMutable.Register>(static () => new TestView()); var result = locator.ResolveView(vm); @@ -298,9 +262,7 @@ public async Task ResolveViewGeneric_ServiceLocatorFallback() await Assert.That(result!.ViewModel).IsEqualTo(vm); } - /// - /// Verifies that generic ResolveView falls back to service locator with a non-empty contract. - /// + /// Verifies that generic ResolveView falls back to service locator with a non-empty contract. /// A task representing the asynchronous test operation. [Test] public async Task ResolveViewGeneric_ServiceLocatorWithContract() @@ -308,7 +270,7 @@ public async Task ResolveViewGeneric_ServiceLocatorWithContract() var locator = new DefaultViewLocator(); var vm = new TestViewModel(); - AppLocator.CurrentMutable.Register>(() => new TestView(), "custom"); + AppLocator.CurrentMutable.Register>(static () => new TestView(), "custom"); var result = locator.ResolveView(vm, "custom"); @@ -316,9 +278,7 @@ public async Task ResolveViewGeneric_ServiceLocatorWithContract() await Assert.That(result!.ViewModel).IsEqualTo(vm); } - /// - /// Verifies that non-generic ResolveView uses generated dispatch and sets ViewModel. - /// + /// Verifies that non-generic ResolveView uses generated dispatch and sets ViewModel. /// A task representing the asynchronous test operation. [Test] public async Task ResolveViewNonGeneric_GeneratedDispatch_SetsViewModel() @@ -335,9 +295,7 @@ public async Task ResolveViewNonGeneric_GeneratedDispatch_SetsViewModel() await Assert.That(result!.ViewModel).IsEqualTo(vm); } - /// - /// Verifies that non-generic ResolveView falls back to mappings when dispatch returns null. - /// + /// Verifies that non-generic ResolveView falls back to mappings when dispatch returns null. /// A task representing the asynchronous test operation. [Test] public async Task ResolveViewNonGeneric_MappingFallback_SetsViewModel() @@ -346,7 +304,7 @@ public async Task ResolveViewNonGeneric_MappingFallback_SetsViewModel() var vm = new TestViewModel { Name = "mapped" }; locator.Map(); - DefaultViewLocator.SetGeneratedViewDispatch((_, _) => null); + DefaultViewLocator.SetGeneratedViewDispatch(static (_, _) => null); var result = locator.ResolveView((object)vm); @@ -354,9 +312,7 @@ public async Task ResolveViewNonGeneric_MappingFallback_SetsViewModel() await Assert.That(result!.ViewModel).IsEqualTo(vm); } - /// - /// Verifies that non-generic ResolveView returns null when no resolution succeeds. - /// + /// Verifies that non-generic ResolveView returns null when no resolution succeeds. /// A task representing the asynchronous test operation. [Test] public async Task ResolveViewNonGeneric_NoMatch_ReturnsNull() @@ -368,9 +324,7 @@ public async Task ResolveViewNonGeneric_NoMatch_ReturnsNull() await Assert.That(result).IsNull(); } - /// - /// Verifies that CreateMappingBuilder returns a builder that registers mappings on this locator. - /// + /// Verifies that CreateMappingBuilder returns a builder that registers mappings on this locator. /// A task representing the asynchronous test operation. [Test] public async Task CreateMappingBuilder_RegistersOnLocator() @@ -378,7 +332,7 @@ public async Task CreateMappingBuilder_RegistersOnLocator() var locator = new DefaultViewLocator(); var builder = locator.CreateMappingBuilder(); - builder.Map(); + _ = builder.Map(); var vm = new TestViewModel(); var result = locator.ResolveView(vm); @@ -387,20 +341,14 @@ public async Task CreateMappingBuilder_RegistersOnLocator() await Assert.That(result).IsTypeOf(); } - /// - /// Simple view model for testing. - /// + /// Simple view model for testing. private sealed class TestViewModel { - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string? Name { get; set; } } - /// - /// Simple view for testing. - /// + /// Simple view for testing. private sealed class TestView : IViewFor { /// diff --git a/src/tests/ReactiveUI.Binding.Tests/View/ViewAttributeTests.cs b/src/tests/ReactiveUI.Binding.Tests/View/ViewAttributeTests.cs index 733927a..ec9fd6b 100644 --- a/src/tests/ReactiveUI.Binding.Tests/View/ViewAttributeTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/View/ViewAttributeTests.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding.Tests.View; -/// -/// Tests for the view registration attribute classes. -/// +/// Tests for the view registration attribute classes. public class ViewAttributeTests { - /// - /// Verifies that ViewContractAttribute stores and returns the contract string. - /// + /// Verifies that ViewContractAttribute stores and returns the contract string. /// A task representing the asynchronous test operation. [Test] public async Task ViewContractAttribute_StoresContract() @@ -21,9 +17,7 @@ public async Task ViewContractAttribute_StoresContract() await Assert.That(attr.Contract).IsEqualTo("compact"); } - /// - /// Verifies that ExcludeFromViewRegistrationAttribute can be instantiated. - /// + /// Verifies that ExcludeFromViewRegistrationAttribute can be instantiated. /// A task representing the asynchronous test operation. [Test] public async Task ExcludeFromViewRegistrationAttribute_CanInstantiate() @@ -33,9 +27,7 @@ public async Task ExcludeFromViewRegistrationAttribute_CanInstantiate() await Assert.That(attr).IsNotNull(); } - /// - /// Verifies that SingleInstanceViewAttribute can be instantiated. - /// + /// Verifies that SingleInstanceViewAttribute can be instantiated. /// A task representing the asynchronous test operation. [Test] public async Task SingleInstanceViewAttribute_CanInstantiate() diff --git a/src/tests/ReactiveUI.Binding.Tests/View/ViewLocatorNotFoundExceptionTests.cs b/src/tests/ReactiveUI.Binding.Tests/View/ViewLocatorNotFoundExceptionTests.cs index 73ccb48..8131b0c 100644 --- a/src/tests/ReactiveUI.Binding.Tests/View/ViewLocatorNotFoundExceptionTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/View/ViewLocatorNotFoundExceptionTests.cs @@ -4,14 +4,10 @@ namespace ReactiveUI.Binding.Tests.View; -/// -/// Tests for the class. -/// +/// Tests for the class. public class ViewLocatorNotFoundExceptionTests { - /// - /// Verifies that the default constructor creates an exception with a default message. - /// + /// Verifies that the default constructor creates an exception with a default message. /// A task representing the asynchronous test operation. [Test] public async Task DefaultConstructor_HasMessage() @@ -22,9 +18,7 @@ public async Task DefaultConstructor_HasMessage() await Assert.That(ex.Message).Contains("IViewLocator"); } - /// - /// Verifies that the message constructor preserves the message. - /// + /// Verifies that the message constructor preserves the message. /// A task representing the asynchronous test operation. [Test] public async Task MessageConstructor_PreservesMessage() @@ -34,9 +28,7 @@ public async Task MessageConstructor_PreservesMessage() await Assert.That(ex.Message).IsEqualTo("custom message"); } - /// - /// Verifies that the message+inner constructor preserves both. - /// + /// Verifies that the message+inner constructor preserves both. /// A task representing the asynchronous test operation. [Test] public async Task MessageAndInnerConstructor_PreservesBoth() diff --git a/src/tests/ReactiveUI.Binding.Tests/View/ViewLocatorTests.cs b/src/tests/ReactiveUI.Binding.Tests/View/ViewLocatorTests.cs index 99d78b4..2282f06 100644 --- a/src/tests/ReactiveUI.Binding.Tests/View/ViewLocatorTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/View/ViewLocatorTests.cs @@ -8,16 +8,12 @@ namespace ReactiveUI.Binding.Tests.View; -/// -/// Tests for the static accessor. -/// +/// Tests for the static accessor. [NotInParallel] [TestExecutor] public class ViewLocatorTests { - /// - /// Verifies that GetCurrent returns a locator when one is registered. - /// + /// Verifies that GetCurrent returns a locator when one is registered. /// A task representing the asynchronous test operation. [Test] public async Task GetCurrent_WhenRegistered_ReturnsLocator() @@ -29,9 +25,7 @@ public async Task GetCurrent_WhenRegistered_ReturnsLocator() await Assert.That(locator).IsTypeOf(); } - /// - /// Verifies that GetCurrent throws ViewLocatorNotFoundException when no locator is registered. - /// + /// Verifies that GetCurrent throws ViewLocatorNotFoundException when no locator is registered. /// A task representing the asynchronous test operation. [Test] public async Task GetCurrent_NotRegistered_ThrowsViewLocatorNotFoundException() diff --git a/src/tests/ReactiveUI.Binding.Tests/View/ViewMappingBuilderTests.cs b/src/tests/ReactiveUI.Binding.Tests/View/ViewMappingBuilderTests.cs index 88d076e..bd77c89 100644 --- a/src/tests/ReactiveUI.Binding.Tests/View/ViewMappingBuilderTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/View/ViewMappingBuilderTests.cs @@ -7,16 +7,12 @@ namespace ReactiveUI.Binding.Tests.View; -/// -/// Tests for the fluent API. -/// +/// Tests for the fluent API. [NotInParallel] [TestExecutor] public class ViewMappingBuilderTests { - /// - /// Verifies that Map registers a mapping that the locator can resolve. - /// + /// Verifies that Map registers a mapping that the locator can resolve. /// A task representing the asynchronous test operation. [Test] public async Task Map_RegistersMapping() @@ -24,16 +20,14 @@ public async Task Map_RegistersMapping() var locator = new DefaultViewLocator(); var builder = new ViewMappingBuilder(locator); - builder.Map(); + _ = builder.Map(); var result = locator.ResolveView(new TestViewModel()); await Assert.That(result).IsNotNull(); await Assert.That(result).IsTypeOf(); } - /// - /// Verifies that Map returns the builder for chaining. - /// + /// Verifies that Map returns the builder for chaining. /// A task representing the asynchronous test operation. [Test] public async Task Map_ReturnsSelfForChaining() @@ -46,9 +40,7 @@ public async Task Map_ReturnsSelfForChaining() await Assert.That(returned).IsEqualTo(builder); } - /// - /// Verifies that multiple mappings can be chained. - /// + /// Verifies that multiple mappings can be chained. /// A task representing the asynchronous test operation. [Test] public async Task Map_MultipleChained() @@ -56,7 +48,7 @@ public async Task Map_MultipleChained() var locator = new DefaultViewLocator(); var builder = new ViewMappingBuilder(locator); - builder + _ = builder .Map() .Map(); @@ -67,9 +59,7 @@ public async Task Map_MultipleChained() await Assert.That(result2).IsNotNull(); } - /// - /// Verifies that Map with factory delegates to the locator. - /// + /// Verifies that Map with factory delegates to the locator. /// A task representing the asynchronous test operation. [Test] public async Task MapWithFactory_RegistersFactory() @@ -78,32 +68,26 @@ public async Task MapWithFactory_RegistersFactory() var builder = new ViewMappingBuilder(locator); var factoryCalled = false; - builder.Map(() => + _ = builder.Map(() => { factoryCalled = true; return new TestView(); }); - locator.ResolveView(new TestViewModel()); + _ = locator.ResolveView(new TestViewModel()); await Assert.That(factoryCalled).IsTrue(); } - /// - /// Simple view model for testing. - /// - [SuppressMessage("Minor Code Smell", "S2094:Classes should not be empty", Justification = "Used for testing")] + /// Simple view model for testing. + [SuppressMessage("Design", "SST1436:Empty type", Justification = "The mapping tests key off the type identity alone.")] private sealed class TestViewModel; - /// - /// Another view model for testing multiple mappings. - /// - [SuppressMessage("Minor Code Smell", "S2094:Classes should not be empty", Justification = "Used for testing")] + /// Another view model for testing multiple mappings. + [SuppressMessage("Design", "SST1436:Empty type", Justification = "The mapping tests key off the type identity alone.")] private sealed class OtherViewModel; - /// - /// Simple view for testing. - /// + /// Simple view for testing. private sealed class TestView : IViewFor { /// @@ -117,9 +101,7 @@ private sealed class TestView : IViewFor } } - /// - /// Another view for testing multiple mappings. - /// + /// Another view for testing multiple mappings. private sealed class OtherView : IViewFor { /// diff --git a/src/tests/ReactiveUI.Binding.Tests/WhenAny/ExpressionChainTests.cs b/src/tests/ReactiveUI.Binding.Tests/WhenAny/ExpressionChainTests.cs index 49f0010..d61c40d 100644 --- a/src/tests/ReactiveUI.Binding.Tests/WhenAny/ExpressionChainTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/WhenAny/ExpressionChainTests.cs @@ -8,19 +8,13 @@ namespace ReactiveUI.Binding.Tests.WhenAny; -/// -/// Tests for SubscribeToExpressionChain with various options. -/// +/// Tests for SubscribeToExpressionChain with various options. public class ExpressionChainTests { - /// - /// The expected number of emitted values when two notifications are produced. - /// + /// The expected number of emitted values when two notifications are produced. private const int ExpectedTwoEmissions = 2; - /// - /// Verifies basic usage notifies on change. - /// + /// Verifies basic usage notifies on change. /// A task representing the asynchronous test operation. [Test] public async Task BasicUsage_NotifiesOnChange() @@ -36,7 +30,7 @@ public async Task BasicUsage_NotifiesOnChange() false, false, true) - .Select(x => x.Value) + .Select(static x => x.Value) .Subscribe(values.Add); await Assert.That(values.Count).IsGreaterThanOrEqualTo(1); @@ -48,9 +42,7 @@ public async Task BasicUsage_NotifiesOnChange() await Assert.That(values[1]).IsEqualTo("End"); } - /// - /// Verifies that before-change notification works via expression chain. - /// + /// Verifies that before-change notification works via expression chain. /// A task representing the asynchronous test operation. [Test] public async Task WithBeforeChange_NotifiesBeforeChange() @@ -66,7 +58,7 @@ public async Task WithBeforeChange_NotifiesBeforeChange() true, false, false) - .Select(x => x.Value) + .Select(static x => x.Value) .Subscribe(values.Add); await Assert.That(values.Count).IsGreaterThanOrEqualTo(1); @@ -77,9 +69,7 @@ public async Task WithBeforeChange_NotifiesBeforeChange() await Assert.That(values.Count).IsGreaterThanOrEqualTo(ExpectedTwoEmissions); } - /// - /// Verifies that skipInitial skips the first emission. - /// + /// Verifies that skipInitial skips the first emission. /// A task representing the asynchronous test operation. [Test] public async Task WithSkipInitial_SkipsFirstEmission() @@ -92,7 +82,7 @@ public async Task WithSkipInitial_SkipsFirstEmission() using var sub = fixture.SubscribeToExpressionChain( expr.Body) - .Select(x => x.Value) + .Select(static x => x.Value) .Subscribe(values.Add); // Should NOT have emitted the initial value @@ -104,9 +94,7 @@ public async Task WithSkipInitial_SkipsFirstEmission() await Assert.That(values[0]).IsEqualTo("Changed"); } - /// - /// Verifies that isDistinct deduplicates same values. - /// + /// Verifies that isDistinct deduplicates same values. /// A task representing the asynchronous test operation. [Test] public async Task WithIsDistinct_DeduplicatesSameValues() @@ -119,7 +107,7 @@ public async Task WithIsDistinct_DeduplicatesSameValues() using var sub = fixture.SubscribeToExpressionChain( expr.Body) - .Select(x => x.Value) + .Select(static x => x.Value) .Subscribe(values.Add); fixture.IsNotNullString = "A"; @@ -131,9 +119,7 @@ public async Task WithIsDistinct_DeduplicatesSameValues() await Assert.That(values[1]).IsEqualTo("B"); } - /// - /// Verifies that null in a chain propagates correctly. - /// + /// Verifies that null in a chain propagates correctly. /// A task representing the asynchronous test operation. [Test] public async Task NullInChain_PropagatesCorrectly() @@ -158,14 +144,12 @@ public async Task NullInChain_PropagatesCorrectly() await Assert.That(values.Count).IsGreaterThanOrEqualTo(1); } - /// - /// Resets and initializes the ReactiveUI binding infrastructure for testing. - /// + /// Resets and initializes the ReactiveUI binding infrastructure for testing. internal static void EnsureInitialized() { RxBindingBuilder.ResetForTesting(); var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - builder.WithCoreServices(); - builder.BuildApp(); + _ = builder.WithCoreServices(); + _ = builder.BuildApp(); } } diff --git a/src/tests/ReactiveUI.Binding.Tests/WhenAny/ObservableForPropertyTests.cs b/src/tests/ReactiveUI.Binding.Tests/WhenAny/ObservableForPropertyTests.cs index 9cf9940..427a8db 100644 --- a/src/tests/ReactiveUI.Binding.Tests/WhenAny/ObservableForPropertyTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/WhenAny/ObservableForPropertyTests.cs @@ -8,34 +8,25 @@ namespace ReactiveUI.Binding.Tests.WhenAny; -/// -/// Tests for ObservableForProperty extension methods using the runtime fallback path. -/// +/// Tests for ObservableForProperty extension methods using the runtime fallback path. public class ObservableForPropertyTests { - /// - /// The name of the property observed by the string-based overload tests. - /// + /// The age assigned to the sample view model. + private const int SampleAge = 42; + + /// The name of the property observed by the string-based overload tests. private const string ObservedPropertyName = "IsNotNullString"; - /// - /// The initial property value used across tests. - /// + /// The initial property value used across tests. private const string InitialValue = "Initial"; - /// - /// The expected number of emitted changes when two notifications are produced. - /// + /// The expected number of emitted changes when two notifications are produced. private const int ExpectedTwoChanges = 2; - /// - /// The updated leaf value used in deep-chain tests. - /// + /// The updated leaf value used in deep-chain tests. private const int UpdatedLeafValue = 99; - /// - /// Verifies that a single property emits on change. - /// + /// Verifies that a single property emits on change. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_EmitsOnChange() @@ -56,9 +47,7 @@ public async Task SingleProperty_EmitsOnChange() await Assert.That(changes[1].Value).IsEqualTo("Baz"); } - /// - /// Verifies that ObservableForProperty skips the initial value by default. - /// + /// Verifies that ObservableForProperty skips the initial value by default. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_SkipsInitialByDefault() @@ -75,9 +64,7 @@ public async Task SingleProperty_SkipsInitialByDefault() await Assert.That(changes.Count).IsEqualTo(0); } - /// - /// Verifies that ObservableForProperty emits the initial value when skipInitial is false. - /// + /// Verifies that ObservableForProperty emits the initial value when skipInitial is false. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_EmitsInitialWhenRequested() @@ -94,9 +81,7 @@ public async Task SingleProperty_EmitsInitialWhenRequested() await Assert.That(changes[0].Value).IsEqualTo(InitialValue); } - /// - /// Verifies that a deep property chain emits when the leaf property changes. - /// + /// Verifies that a deep property chain emits when the leaf property changes. /// A task representing the asynchronous test operation. [Test] public async Task DeepChain_EmitsOnLeafChange() @@ -116,9 +101,7 @@ public async Task DeepChain_EmitsOnLeafChange() await Assert.That(changes.Count).IsGreaterThanOrEqualTo(ExpectedTwoChanges); } - /// - /// Verifies that a deep chain resubscribes when an intermediate object changes. - /// + /// Verifies that a deep chain resubscribes when an intermediate object changes. /// A task representing the asynchronous test operation. [Test] public async Task DeepChain_ResubscribesOnIntermediateChange() @@ -139,9 +122,7 @@ public async Task DeepChain_ResubscribesOnIntermediateChange() await Assert.That(changes.Count).IsGreaterThan(initialCount); } - /// - /// Verifies that a deep chain handles null intermediate objects gracefully. - /// + /// Verifies that a deep chain handles null intermediate objects gracefully. /// A task representing the asynchronous test operation. [Test] public async Task DeepChain_ResubscribesAfterNullThenRestore() @@ -165,16 +146,14 @@ public async Task DeepChain_ResubscribesAfterNullThenRestore() await Assert.That(changes.Count).IsGreaterThan(countAfterInitial); } - /// - /// Verifies that a four-level deep chain triggers updates at any level. - /// + /// Verifies that a four-level deep chain triggers updates at any level. /// A task representing the asynchronous test operation. [Test] public async Task FourLevelDeepChain_AnyLevelTriggersUpdate() { EnsureInitialized(); - var fixture = new ObjChain1 { Chain2 = new() { Chain3 = new() { Host = new() { SomeOtherParam = 42 } } } }; + var fixture = new ObjChain1 { Chain2 = new() { Chain3 = new() { Host = new() { SomeOtherParam = SampleAge } } } }; var values = new List>(); using var sub = fixture.ObservableForProperty( @@ -190,14 +169,8 @@ public async Task FourLevelDeepChain_AnyLevelTriggersUpdate() await Assert.That(values.Count).IsGreaterThanOrEqualTo(ExpectedTwoChanges); } - /// - /// Verifies that ObservableForProperty works with plain INPC objects. - /// + /// Verifies that ObservableForProperty works with plain INPC objects. /// A task representing the asynchronous test operation. - [SuppressMessage( - "Minor Code Smell", - "S100:Methods and properties should be named in PascalCase", - Justification = "established acronym matching ReactiveUI domain terminology")] [Test] public async Task WorksWithINPCObjects() { @@ -215,9 +188,7 @@ public async Task WorksWithINPCObjects() await Assert.That(changes[0].Value).IsEqualTo("Hello"); } - /// - /// Verifies that the string-based overload of ObservableForProperty works. - /// + /// Verifies that the string-based overload of ObservableForProperty works. /// A task representing the asynchronous test operation. [Test] public async Task StringOverload_ObservesProperty() @@ -236,9 +207,7 @@ public async Task StringOverload_ObservesProperty() await Assert.That(changes[0].Value).IsEqualTo("Test"); } - /// - /// Verifies that ObservableForProperty deduplicates same values by default. - /// + /// Verifies that ObservableForProperty deduplicates same values by default. /// A task representing the asynchronous test operation. [Test] public async Task IsDistinct_DeduplicatesSameValues() @@ -257,9 +226,7 @@ public async Task IsDistinct_DeduplicatesSameValues() await Assert.That(changes.Count).IsEqualTo(1); } - /// - /// Verifies that the string-based overload emits the initial value when skipInitial is false. - /// + /// Verifies that the string-based overload emits the initial value when skipInitial is false. /// A task representing the asynchronous test operation. [Test] public async Task StringOverload_SkipInitialFalse_EmitsInitialValue() @@ -276,9 +243,7 @@ public async Task StringOverload_SkipInitialFalse_EmitsInitialValue() await Assert.That(changes[0].Value).IsEqualTo(InitialValue); } - /// - /// Verifies that the string-based overload works with isDistinct false. - /// + /// Verifies that the string-based overload works with isDistinct false. /// A task representing the asynchronous test operation. [Test] public async Task StringOverload_IsDistinctFalse_EmitsAll() @@ -297,9 +262,7 @@ public async Task StringOverload_IsDistinctFalse_EmitsAll() await Assert.That(changes.Count).IsGreaterThanOrEqualTo(ExpectedTwoChanges); } - /// - /// Verifies that the string-based overload works with beforeChange true. - /// + /// Verifies that the string-based overload works with beforeChange true. /// A task representing the asynchronous test operation. [Test] public async Task StringOverload_BeforeChange_EmitsBeforePropertyChanges() @@ -317,9 +280,7 @@ public async Task StringOverload_BeforeChange_EmitsBeforePropertyChanges() await Assert.That(changes.Count).IsGreaterThanOrEqualTo(1); } - /// - /// Verifies that the expression-based overload works with isDistinct false. - /// + /// Verifies that the expression-based overload works with isDistinct false. /// A task representing the asynchronous test operation. [Test] public async Task ExpressionOverload_IsDistinctFalse_EmitsAll() @@ -338,9 +299,7 @@ public async Task ExpressionOverload_IsDistinctFalse_EmitsAll() await Assert.That(changes.Count).IsGreaterThanOrEqualTo(ExpectedTwoChanges); } - /// - /// Verifies that the expression-based overload works with beforeChange true. - /// + /// Verifies that the expression-based overload works with beforeChange true. /// A task representing the asynchronous test operation. [Test] public async Task ExpressionOverload_BeforeChange_EmitsBeforePropertyChanges() @@ -360,7 +319,7 @@ public async Task ExpressionOverload_BeforeChange_EmitsBeforePropertyChanges() /// /// Verifies that the string-based overload handles a non-existent property name gracefully. - /// Covers the catch block at ReactiveNotifyPropertyChangedMixin lines 65-68 where + /// Covers the catch block at ReactiveNotifyPropertyChangedMixins lines 65-68 where /// Expression.Property throws and falls back to the parameter expression. /// /// A task representing the asynchronous test operation. @@ -383,7 +342,7 @@ public async Task StringOverload_NonExistentProperty_DoesNotThrow() /// /// Verifies that ObservableForProperty by name returns default when the property cannot be found via reflection. - /// Covers ReactiveNotifyPropertyChangedMixin.cs line 82 (prop is null path in GetCurrentValue). + /// Covers ReactiveNotifyPropertyChangedMixins.cs line 82 (prop is null path in GetCurrentValue). /// /// A task representing the asynchronous test operation. [Test] @@ -415,7 +374,7 @@ public async Task StringOverload_PropertyNotFoundViaReflection_ReturnsDefault() /// /// Verifies that the SubscribeToExpressionChain val cast branch is exercised. - /// Covers ReactiveNotifyPropertyChangedMixin.cs line 211 (val is not null and val is not TValue). + /// Covers ReactiveNotifyPropertyChangedMixins.cs line 211 (val is not null and val is not TValue). /// When val is null, the condition evaluates differently. /// /// A task representing the asynchronous test operation. @@ -441,14 +400,12 @@ public async Task SubscribeToExpressionChain_NullValue_PassesThroughAsDefault() await Assert.That(values[0].Value).IsNull(); } - /// - /// Resets and initializes the ReactiveUI binding infrastructure for testing. - /// + /// Resets and initializes the ReactiveUI binding infrastructure for testing. internal static void EnsureInitialized() { RxBindingBuilder.ResetForTesting(); var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - builder.WithCoreServices(); - builder.BuildApp(); + _ = builder.WithCoreServices(); + _ = builder.BuildApp(); } } diff --git a/src/tests/ReactiveUI.Binding.Tests/WhenAny/WhenAnyObservableTests.cs b/src/tests/ReactiveUI.Binding.Tests/WhenAny/WhenAnyObservableTests.cs index 18bc232..5217bdf 100644 --- a/src/tests/ReactiveUI.Binding.Tests/WhenAny/WhenAnyObservableTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/WhenAny/WhenAnyObservableTests.cs @@ -8,54 +8,34 @@ namespace ReactiveUI.Binding.Tests.WhenAny; -/// -/// Tests for WhenAnyObservable extension methods. -/// +/// Tests for WhenAnyObservable extension methods. public class WhenAnyObservableTests { - /// - /// A sample value emitted by a single observable. - /// + /// A sample value emitted by a single observable. private const int SampleValue = 42; - /// - /// The second value emitted when merging two observables. - /// + /// The second value emitted when merging two observables. private const int SecondValue = 2; - /// - /// The expected number of merged emissions from two observables. - /// + /// The expected number of merged emissions from two observables. private const int ExpectedTwoEmissions = 2; - /// - /// The first value emitted in the three-observable combining test. - /// + /// The first value emitted in the three-observable combining test. private const int FirstCombineValue = 10; - /// - /// The second value emitted in the three-observable combining test. - /// + /// The second value emitted in the three-observable combining test. private const int SecondCombineValue = 20; - /// - /// The third value emitted in the three-observable combining test. - /// + /// The third value emitted in the three-observable combining test. private const int ThirdCombineValue = 30; - /// - /// The expected number of emissions when combining three observables. - /// + /// The expected number of emissions when combining three observables. private const int ExpectedThreeEmissions = 3; - /// - /// A value emitted by a late-assigned observable. - /// + /// A value emitted by a late-assigned observable. private const int LateAssignedValue = 99; - /// - /// Verifies that null observables do not cause exceptions. - /// + /// Verifies that null observables do not cause exceptions. /// A task representing the asynchronous test operation. [Test] public async Task NullObservablesDoNotCauseExceptions() @@ -79,9 +59,7 @@ public async Task NullObservablesDoNotCauseExceptions() await Assert.That(values[0]).IsEqualTo(SampleValue); } - /// - /// Verifies that merging two observable properties works. - /// + /// Verifies that merging two observable properties works. /// A task representing the asynchronous test operation. [Test] public async Task SmokeTestMerging() @@ -104,9 +82,7 @@ public async Task SmokeTestMerging() await Assert.That(values).Contains(SecondValue); } - /// - /// Verifies that combining three observable properties works. - /// + /// Verifies that combining three observable properties works. /// A task representing the asynchronous test operation. [Test] public async Task SmokeTestCombining() @@ -129,9 +105,7 @@ public async Task SmokeTestCombining() await Assert.That(values.Count).IsEqualTo(ExpectedThreeEmissions); } - /// - /// Verifies that a null object updates when a non-null observable is assigned. - /// + /// Verifies that a null object updates when a non-null observable is assigned. /// A task representing the asynchronous test operation. [Test] public async Task NullObjectUpdatesWhenNotNullAnymore() @@ -157,14 +131,12 @@ public async Task NullObjectUpdatesWhenNotNullAnymore() await Assert.That(values[0]).IsEqualTo(LateAssignedValue); } - /// - /// Resets and initializes the ReactiveUI binding infrastructure for testing. - /// + /// Resets and initializes the ReactiveUI binding infrastructure for testing. internal static void EnsureInitialized() { RxBindingBuilder.ResetForTesting(); var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - builder.WithCoreServices(); - builder.BuildApp(); + _ = builder.WithCoreServices(); + _ = builder.BuildApp(); } } diff --git a/src/tests/ReactiveUI.Binding.Tests/WhenAny/WhenAnyTests.cs b/src/tests/ReactiveUI.Binding.Tests/WhenAny/WhenAnyTests.cs index fe80a14..0e33dd6 100644 --- a/src/tests/ReactiveUI.Binding.Tests/WhenAny/WhenAnyTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/WhenAny/WhenAnyTests.cs @@ -7,19 +7,13 @@ namespace ReactiveUI.Binding.Tests.WhenAny; -/// -/// Tests for the WhenAny extension methods which provide IObservedChange context. -/// +/// Tests for the WhenAny extension methods which provide IObservedChange context. public class WhenAnyTests { - /// - /// The expected number of emitted values after the second notification. - /// + /// The expected number of emitted values after the second notification. private const int ExpectedTwoEmissions = 2; - /// - /// Verifies that WhenAny with a single property and selector returns the selector result. - /// + /// Verifies that WhenAny with a single property and selector returns the selector result. /// A task representing the asynchronous test operation. [Test] public async Task SingleProperty_WithSelector_ReturnsObservedChange() @@ -31,7 +25,7 @@ public async Task SingleProperty_WithSelector_ReturnsObservedChange() using var sub = fixture.WhenAny( x => x.IsNotNullString, - change => change.Value) + static change => change.Value) .Subscribe(values.Add); await Assert.That(values.Count).IsGreaterThanOrEqualTo(1); @@ -43,9 +37,7 @@ public async Task SingleProperty_WithSelector_ReturnsObservedChange() await Assert.That(values[1]).IsEqualTo("Changed"); } - /// - /// Verifies that WhenAny with two properties combines their observed changes. - /// + /// Verifies that WhenAny with two properties combines their observed changes. /// A task representing the asynchronous test operation. [Test] public async Task TwoProperties_CombinesWithSelector() @@ -58,16 +50,14 @@ public async Task TwoProperties_CombinesWithSelector() using var sub = fixture.WhenAny( x => x.IsNotNullString, x => x.IsOnlyOneWord, - (c1, c2) => $"{c1.Value} {c2.Value}") + static (c1, c2) => $"{c1.Value} {c2.Value}") .Subscribe(values.Add); await Assert.That(values.Count).IsGreaterThanOrEqualTo(1); await Assert.That(values[0]).IsEqualTo("Hello World"); } - /// - /// Verifies that WhenAny returns the current value on subscription. - /// + /// Verifies that WhenAny returns the current value on subscription. /// A task representing the asynchronous test operation. [Test] public async Task ReturnsCurrentValueOnSubscription() @@ -79,16 +69,14 @@ public async Task ReturnsCurrentValueOnSubscription() using var sub = fixture.WhenAny( x => x.IsNotNullString, - change => change.Value) + static change => change.Value) .Subscribe(values.Add); await Assert.That(values.Count).IsGreaterThanOrEqualTo(1); await Assert.That(values[0]).IsEqualTo("PreExisting"); } - /// - /// Verifies that WhenAny works with plain INPC objects. - /// + /// Verifies that WhenAny works with plain INPC objects. /// A task representing the asynchronous test operation. [Test] public async Task WorksWithINotifyPropertyChangedObjects() @@ -100,7 +88,7 @@ public async Task WorksWithINotifyPropertyChangedObjects() using var sub = obj.WhenAny( x => x.InpcProperty, - change => change.Value) + static change => change.Value) .Subscribe(values.Add); await Assert.That(values.Count).IsGreaterThanOrEqualTo(1); @@ -111,9 +99,7 @@ public async Task WorksWithINotifyPropertyChangedObjects() await Assert.That(values.Count).IsGreaterThanOrEqualTo(ExpectedTwoEmissions); } - /// - /// Verifies that WhenAny exposes the sender through the observed change. - /// + /// Verifies that WhenAny exposes the sender through the observed change. /// A task representing the asynchronous test operation. [Test] public async Task ExposesSenderThroughObservedChange() @@ -125,21 +111,19 @@ public async Task ExposesSenderThroughObservedChange() using var sub = fixture.WhenAny( x => x.IsNotNullString, - change => change) + static change => change) .Subscribe(c => captured = c); await Assert.That(captured).IsNotNull(); await Assert.That(captured!.Sender).IsEqualTo(fixture); } - /// - /// Resets and initializes the ReactiveUI binding infrastructure for testing. - /// + /// Resets and initializes the ReactiveUI binding infrastructure for testing. internal static void EnsureInitialized() { RxBindingBuilder.ResetForTesting(); var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - builder.WithCoreServices(); - builder.BuildApp(); + _ = builder.WithCoreServices(); + _ = builder.BuildApp(); } } diff --git a/src/tests/ReactiveUI.Binding.Tests/WhenAny/WhenAnyValueMultiPropertyTests.cs b/src/tests/ReactiveUI.Binding.Tests/WhenAny/WhenAnyValueMultiPropertyTests.cs index a36e8c2..5520be4 100644 --- a/src/tests/ReactiveUI.Binding.Tests/WhenAny/WhenAnyValueMultiPropertyTests.cs +++ b/src/tests/ReactiveUI.Binding.Tests/WhenAny/WhenAnyValueMultiPropertyTests.cs @@ -7,29 +7,19 @@ namespace ReactiveUI.Binding.Tests.WhenAny; -/// -/// Tests for WhenAnyValue with multi-property overloads (1 through 12 properties). -/// +/// Tests for WhenAnyValue with multi-property overloads (1 through 12 properties). public class WhenAnyValueMultiPropertyTests { - /// - /// The expected number of emissions after three successive value changes. - /// + /// The expected number of emissions after three successive value changes. private const int ExpectedThreeEmissions = 3; - /// - /// The index of the third emitted value. - /// + /// The index of the third emitted value. private const int ThirdValueIndex = 2; - /// - /// The expected number of emissions after a deep-chain value change. - /// + /// The expected number of emissions after a deep-chain value change. private const int ExpectedTwoEmissions = 2; - /// - /// Verifies that WhenAnyValue with 1 property emits values. - /// + /// Verifies that WhenAnyValue with 1 property emits values. /// A task representing the asynchronous test operation. [Test] public async Task WhenAnyValue_1Property() @@ -46,9 +36,7 @@ public async Task WhenAnyValue_1Property() await Assert.That(values[0]).IsEqualTo("A"); } - /// - /// Verifies that WhenAnyValue with 2 properties emits tuples. - /// + /// Verifies that WhenAnyValue with 2 properties emits tuples. /// A task representing the asynchronous test operation. [Test] public async Task WhenAnyValue_2Properties() @@ -66,9 +54,7 @@ public async Task WhenAnyValue_2Properties() await Assert.That(values[0].property2).IsEqualTo("B"); } - /// - /// Verifies that WhenAnyValue with 3 properties emits tuples. - /// + /// Verifies that WhenAnyValue with 3 properties emits tuples. /// A task representing the asynchronous test operation. [Test] public async Task WhenAnyValue_3Properties() @@ -87,9 +73,7 @@ public async Task WhenAnyValue_3Properties() await Assert.That(values[0].property3).IsEqualTo("C"); } - /// - /// Verifies that WhenAnyValue with 4 properties emits tuples. - /// + /// Verifies that WhenAnyValue with 4 properties emits tuples. /// A task representing the asynchronous test operation. [Test] public async Task WhenAnyValue_4Properties() @@ -111,23 +95,14 @@ public async Task WhenAnyValue_4Properties() await Assert.That(values[0].property4).IsEqualTo("D"); } - /// - /// Verifies that WhenAnyValue with 5 properties emits tuples. - /// + /// Verifies that WhenAnyValue with 5 properties emits tuples. /// A task representing the asynchronous test operation. [Test] public async Task WhenAnyValue_5Properties() { EnsureInitialized(); - var fixture = new WhenAnyTestFixture - { - Value1 = "A", - Value2 = "B", - Value3 = "C", - Value4 = "D", - Value5 = "E" - }; + var fixture = new WhenAnyTestFixture { Value1 = "A", Value2 = "B", Value3 = "C", Value4 = "D", Value5 = "E" }; var values = new List<(string property1, string property2, string property3, string property4, string property5)>(); @@ -144,24 +119,14 @@ public async Task WhenAnyValue_5Properties() await Assert.That(values[0].property5).IsEqualTo("E"); } - /// - /// Verifies that WhenAnyValue with 6 properties emits tuples. - /// + /// Verifies that WhenAnyValue with 6 properties emits tuples. /// A task representing the asynchronous test operation. [Test] public async Task WhenAnyValue_6Properties() { EnsureInitialized(); - var fixture = new WhenAnyTestFixture - { - Value1 = "A", - Value2 = "B", - Value3 = "C", - Value4 = "D", - Value5 = "E", - Value6 = "F" - }; + var fixture = new WhenAnyTestFixture { Value1 = "A", Value2 = "B", Value3 = "C", Value4 = "D", Value5 = "E", Value6 = "F" }; var values = new List<(string property1, string property2, string property3, string property4, string property5, string property6)>(); @@ -180,25 +145,14 @@ public async Task WhenAnyValue_6Properties() await Assert.That(values[0].property6).IsEqualTo("F"); } - /// - /// Verifies that WhenAnyValue with 7 properties emits tuples. - /// + /// Verifies that WhenAnyValue with 7 properties emits tuples. /// A task representing the asynchronous test operation. [Test] public async Task WhenAnyValue_7Properties() { EnsureInitialized(); - var fixture = new WhenAnyTestFixture - { - Value1 = "A", - Value2 = "B", - Value3 = "C", - Value4 = "D", - Value5 = "E", - Value6 = "F", - Value7 = "G" - }; + var fixture = new WhenAnyTestFixture { Value1 = "A", Value2 = "B", Value3 = "C", Value4 = "D", Value5 = "E", Value6 = "F", Value7 = "G" }; var values = new List<(string property1, string property2, string property3, string property4, string property5, string property6, string property7)>(); @@ -217,26 +171,14 @@ public async Task WhenAnyValue_7Properties() await Assert.That(values[0].property7).IsEqualTo("G"); } - /// - /// Verifies that WhenAnyValue with 8 properties emits tuples. - /// + /// Verifies that WhenAnyValue with 8 properties emits tuples. /// A task representing the asynchronous test operation. [Test] public async Task WhenAnyValue_8Properties() { EnsureInitialized(); - var fixture = new WhenAnyTestFixture - { - Value1 = "A", - Value2 = "B", - Value3 = "C", - Value4 = "D", - Value5 = "E", - Value6 = "F", - Value7 = "G", - Value8 = "H" - }; + var fixture = new WhenAnyTestFixture { Value1 = "A", Value2 = "B", Value3 = "C", Value4 = "D", Value5 = "E", Value6 = "F", Value7 = "G", Value8 = "H" }; string? lastItem8 = null; @@ -254,27 +196,14 @@ public async Task WhenAnyValue_8Properties() await Assert.That(lastItem8).IsEqualTo("H"); } - /// - /// Verifies that WhenAnyValue with 9 properties emits tuples. - /// + /// Verifies that WhenAnyValue with 9 properties emits tuples. /// A task representing the asynchronous test operation. [Test] public async Task WhenAnyValue_9Properties() { EnsureInitialized(); - var fixture = new WhenAnyTestFixture - { - Value1 = "A", - Value2 = "B", - Value3 = "C", - Value4 = "D", - Value5 = "E", - Value6 = "F", - Value7 = "G", - Value8 = "H", - Value9 = "I" - }; + var fixture = new WhenAnyTestFixture { Value1 = "A", Value2 = "B", Value3 = "C", Value4 = "D", Value5 = "E", Value6 = "F", Value7 = "G", Value8 = "H", Value9 = "I" }; string? lastItem9 = null; @@ -293,28 +222,14 @@ public async Task WhenAnyValue_9Properties() await Assert.That(lastItem9).IsEqualTo("I"); } - /// - /// Verifies that WhenAnyValue with 10 properties emits tuples. - /// + /// Verifies that WhenAnyValue with 10 properties emits tuples. /// A task representing the asynchronous test operation. [Test] public async Task WhenAnyValue_10Properties() { EnsureInitialized(); - var fixture = new WhenAnyTestFixture - { - Value1 = "A", - Value2 = "B", - Value3 = "C", - Value4 = "D", - Value5 = "E", - Value6 = "F", - Value7 = "G", - Value8 = "H", - Value9 = "I", - Value10 = "J" - }; + var fixture = new WhenAnyTestFixture { Value1 = "A", Value2 = "B", Value3 = "C", Value4 = "D", Value5 = "E", Value6 = "F", Value7 = "G", Value8 = "H", Value9 = "I", Value10 = "J" }; string? lastItem10 = null; @@ -334,9 +249,7 @@ public async Task WhenAnyValue_10Properties() await Assert.That(lastItem10).IsEqualTo("J"); } - /// - /// Verifies that WhenAnyValue with 11 properties emits tuples. - /// + /// Verifies that WhenAnyValue with 11 properties emits tuples. /// A task representing the asynchronous test operation. [Test] public async Task WhenAnyValue_11Properties() @@ -377,9 +290,7 @@ public async Task WhenAnyValue_11Properties() await Assert.That(lastItem11).IsEqualTo("K"); } - /// - /// Verifies that WhenAnyValue with 12 properties emits tuples. - /// + /// Verifies that WhenAnyValue with 12 properties emits tuples. /// A task representing the asynchronous test operation. [Test] public async Task WhenAnyValue_12Properties() @@ -422,9 +333,7 @@ public async Task WhenAnyValue_12Properties() await Assert.That(lastItem12).IsEqualTo("L"); } - /// - /// Verifies that WhenAnyValue with 1 property emits sequential changes. - /// + /// Verifies that WhenAnyValue with 1 property emits sequential changes. /// A task representing the asynchronous test operation. [Test] public async Task WhenAnyValue_1Property_SequentialChanges() @@ -446,9 +355,7 @@ public async Task WhenAnyValue_1Property_SequentialChanges() await Assert.That(values[ThirdValueIndex]).IsEqualTo("C"); } - /// - /// Verifies that WhenAnyValue with 2 properties and a selector works. - /// + /// Verifies that WhenAnyValue with 2 properties and a selector works. /// A task representing the asynchronous test operation. [Test] public async Task WhenAnyValue_2Properties_WithSelector() @@ -461,16 +368,14 @@ public async Task WhenAnyValue_2Properties_WithSelector() using var sub = fixture.WhenAnyValue( x => x.Value1, x => x.Value2, - (v1, v2) => $"{v1} {v2}") + static (v1, v2) => $"{v1} {v2}") .Subscribe(values.Add); await Assert.That(values.Count).IsGreaterThanOrEqualTo(1); await Assert.That(values[0]).IsEqualTo("Hello World"); } - /// - /// Verifies that WhenAnyValue works with deep property chains. - /// + /// Verifies that WhenAnyValue works with deep property chains. /// A task representing the asynchronous test operation. [Test] public async Task WhenAnyValue_DeepChain() @@ -492,14 +397,12 @@ public async Task WhenAnyValue_DeepChain() await Assert.That(values[1]).IsEqualTo("Deeper"); } - /// - /// Resets and initializes the ReactiveUI binding infrastructure for testing. - /// + /// Resets and initializes the ReactiveUI binding infrastructure for testing. internal static void EnsureInitialized() { RxBindingBuilder.ResetForTesting(); var builder = RxBindingBuilder.CreateReactiveUIBindingBuilder(); - builder.WithCoreServices(); - builder.BuildApp(); + _ = builder.WithCoreServices(); + _ = builder.BuildApp(); } } diff --git a/src/tests/Shared/TransitiveAssemblyResolver.cs b/src/tests/Shared/TransitiveAssemblyResolver.cs index e80ac05..022d5a7 100644 --- a/src/tests/Shared/TransitiveAssemblyResolver.cs +++ b/src/tests/Shared/TransitiveAssemblyResolver.cs @@ -43,9 +43,7 @@ internal static void Register() AssemblyLoadContext.Default.Resolving += ResolveByName; } - /// - /// Resolves an assembly by its simple name when the default, version-strict load fails. - /// + /// Resolves an assembly by its simple name when the default, version-strict load fails. /// The load context raising the resolve request. /// The requested assembly name, including the version that could not be found. /// A matching assembly resolved by simple name, or if none is available. @@ -68,7 +66,7 @@ internal static void Register() // Otherwise load the deployed copy from the test output directory, ignoring the // requested version (which may be higher than what the package actually shipped). - var candidate = Path.Combine(AppContext.BaseDirectory, name.Name + ".dll"); + var candidate = Path.Combine(AppContext.BaseDirectory, $"{name.Name}.dll"); return File.Exists(candidate) ? context.LoadFromAssemblyPath(candidate) : null; } } diff --git a/src/tests/SharedScenarios/.editorconfig b/src/tests/SharedScenarios/.editorconfig new file mode 100644 index 0000000..354b2b4 --- /dev/null +++ b/src/tests/SharedScenarios/.editorconfig @@ -0,0 +1,13 @@ +[*.cs] + +################### +# Shared scenario fixtures +# +# These files are not only compiled by their own project - the runtime-execution tests read them as +# text and compile them at C# 7.3 and C# 10 to prove the generated output works on the minimum +# supported language version. A rule whose fix needs a newer language feature would make the +# fixture stop compiling in exactly the test that matters, so those rules are off here. +################### +dotnet_diagnostic.SST2200.severity = none # 'field' is an ordinary identifier before C# 14 +dotnet_diagnostic.SST2202.severity = none # target-typed 'new' is C# 9 +dotnet_diagnostic.PSH1000.severity = none # 'static' lambdas are C# 9 diff --git a/src/tests/SharedScenarios/Bind/MultipleBindings/MyView.cs b/src/tests/SharedScenarios/Bind/MultipleBindings/MyView.cs index 08135f3..dd2c317 100644 --- a/src/tests/SharedScenarios/Bind/MultipleBindings/MyView.cs +++ b/src/tests/SharedScenarios/Bind/MultipleBindings/MyView.cs @@ -7,19 +7,13 @@ namespace SharedScenarios.Bind.MultipleBindings; -/// -/// Target View with multiple properties. -/// +/// Target View with multiple properties. public class MyView : IViewFor, INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _nameText = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private int _ageText; /// @@ -28,9 +22,7 @@ public class MyView : IViewFor, INotifyPropertyChanged /// public object? ViewModel { get; set; } - /// - /// Gets or sets the name text. - /// + /// Gets or sets the name text. public string NameText { get => _nameText; @@ -46,9 +38,7 @@ public string NameText } } - /// - /// Gets or sets the age text. - /// + /// Gets or sets the age text. public int AgeText { get => _ageText; diff --git a/src/tests/SharedScenarios/Bind/MultipleBindings/MyViewModel.cs b/src/tests/SharedScenarios/Bind/MultipleBindings/MyViewModel.cs index d6095f2..8dc58a9 100644 --- a/src/tests/SharedScenarios/Bind/MultipleBindings/MyViewModel.cs +++ b/src/tests/SharedScenarios/Bind/MultipleBindings/MyViewModel.cs @@ -6,27 +6,19 @@ namespace SharedScenarios.Bind.MultipleBindings; -/// -/// Source ViewModel with multiple properties. -/// +/// Source ViewModel with multiple properties. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private int _age; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; @@ -42,9 +34,7 @@ public string Name } } - /// - /// Gets or sets the age. - /// + /// Gets or sets the age. public int Age { get => _age; diff --git a/src/tests/SharedScenarios/Bind/MultipleBindings/Scenario.cs b/src/tests/SharedScenarios/Bind/MultipleBindings/Scenario.cs index a0ebef1..f6f4d81 100644 --- a/src/tests/SharedScenarios/Bind/MultipleBindings/Scenario.cs +++ b/src/tests/SharedScenarios/Bind/MultipleBindings/Scenario.cs @@ -6,19 +6,15 @@ namespace SharedScenarios.Bind.MultipleBindings; -/// -/// Exercises Bind (view-first two-way) with multiple bindings on the same view/vm pair. -/// +/// Exercises Bind (view-first two-way) with multiple bindings on the same view/vm pair. public static class Scenario { - /// - /// Creates multiple two-way bindings using view-first syntax. - /// + /// Creates multiple two-way bindings using view-first syntax. /// The target view. /// The source view model. /// A tuple of bindings. public static (IReactiveBinding name, - IReactiveBinding age) Execute(MyView view, MyViewModel vm) - => (view.Bind(vm, x => x.Name, x => x.NameText), + IReactiveBinding age) Execute(MyView view, MyViewModel vm) => + (view.Bind(vm, x => x.Name, x => x.NameText), view.Bind(vm, x => x.Age, x => x.AgeText)); } diff --git a/src/tests/SharedScenarios/Bind/SinglePropertyStringToString/MyView.cs b/src/tests/SharedScenarios/Bind/SinglePropertyStringToString/MyView.cs index 28e3b8a..23b1d44 100644 --- a/src/tests/SharedScenarios/Bind/SinglePropertyStringToString/MyView.cs +++ b/src/tests/SharedScenarios/Bind/SinglePropertyStringToString/MyView.cs @@ -7,14 +7,10 @@ namespace SharedScenarios.Bind.SinglePropertyStringToString; -/// -/// Target View implementing IViewFor with a string property. -/// +/// Target View implementing IViewFor with a string property. public class MyView : IViewFor, INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _nameText = string.Empty; /// @@ -23,9 +19,7 @@ public class MyView : IViewFor, INotifyPropertyChanged /// public object? ViewModel { get; set; } - /// - /// Gets or sets the name text. - /// + /// Gets or sets the name text. public string NameText { get => _nameText; diff --git a/src/tests/SharedScenarios/Bind/SinglePropertyStringToString/MyViewModel.cs b/src/tests/SharedScenarios/Bind/SinglePropertyStringToString/MyViewModel.cs index 61e5c1d..00e72aa 100644 --- a/src/tests/SharedScenarios/Bind/SinglePropertyStringToString/MyViewModel.cs +++ b/src/tests/SharedScenarios/Bind/SinglePropertyStringToString/MyViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.Bind.SinglePropertyStringToString; -/// -/// Source ViewModel with a string property. -/// +/// Source ViewModel with a string property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; diff --git a/src/tests/SharedScenarios/Bind/SinglePropertyStringToString/Scenario.cs b/src/tests/SharedScenarios/Bind/SinglePropertyStringToString/Scenario.cs index f7bd91f..bd3740e 100644 --- a/src/tests/SharedScenarios/Bind/SinglePropertyStringToString/Scenario.cs +++ b/src/tests/SharedScenarios/Bind/SinglePropertyStringToString/Scenario.cs @@ -6,17 +6,13 @@ namespace SharedScenarios.Bind.SinglePropertyStringToString; -/// -/// Exercises Bind (view-first two-way) with string-to-string property binding. -/// +/// Exercises Bind (view-first two-way) with string-to-string property binding. public static class Scenario { - /// - /// Creates a two-way binding between ViewModel.Name and View.NameText using view-first syntax. - /// + /// Creates a two-way binding between ViewModel.Name and View.NameText using view-first syntax. /// The target view. /// The source view model. /// A reactive binding representing the binding. - public static IReactiveBinding Execute(MyView view, MyViewModel vm) - => view.Bind(vm, x => x.Name, x => x.NameText); + public static IReactiveBinding Execute(MyView view, MyViewModel vm) => + view.Bind(vm, x => x.Name, x => x.NameText); } diff --git a/src/tests/SharedScenarios/Bind/SinglePropertyWithConverters/MyView.cs b/src/tests/SharedScenarios/Bind/SinglePropertyWithConverters/MyView.cs index b187c01..3da9877 100644 --- a/src/tests/SharedScenarios/Bind/SinglePropertyWithConverters/MyView.cs +++ b/src/tests/SharedScenarios/Bind/SinglePropertyWithConverters/MyView.cs @@ -7,14 +7,10 @@ namespace SharedScenarios.Bind.SinglePropertyWithConverters; -/// -/// Target View with a string property. -/// +/// Target View with a string property. public class MyView : IViewFor, INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _countText = string.Empty; /// @@ -23,9 +19,7 @@ public class MyView : IViewFor, INotifyPropertyChanged /// public object? ViewModel { get; set; } - /// - /// Gets or sets the count text. - /// + /// Gets or sets the count text. public string CountText { get => _countText; diff --git a/src/tests/SharedScenarios/Bind/SinglePropertyWithConverters/MyViewModel.cs b/src/tests/SharedScenarios/Bind/SinglePropertyWithConverters/MyViewModel.cs index d0420e0..2a57e63 100644 --- a/src/tests/SharedScenarios/Bind/SinglePropertyWithConverters/MyViewModel.cs +++ b/src/tests/SharedScenarios/Bind/SinglePropertyWithConverters/MyViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.Bind.SinglePropertyWithConverters; -/// -/// Source ViewModel with an integer property. -/// +/// Source ViewModel with an integer property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private int _count; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the count. - /// + /// Gets or sets the count. public int Count { get => _count; diff --git a/src/tests/SharedScenarios/Bind/SinglePropertyWithConverters/Scenario.cs b/src/tests/SharedScenarios/Bind/SinglePropertyWithConverters/Scenario.cs index ba7d3b6..ac16991 100644 --- a/src/tests/SharedScenarios/Bind/SinglePropertyWithConverters/Scenario.cs +++ b/src/tests/SharedScenarios/Bind/SinglePropertyWithConverters/Scenario.cs @@ -6,17 +6,13 @@ namespace SharedScenarios.Bind.SinglePropertyWithConverters; -/// -/// Exercises Bind (view-first two-way) with conversion functions between int and string. -/// +/// Exercises Bind (view-first two-way) with conversion functions between int and string. public static class Scenario { - /// - /// Creates a two-way binding between ViewModel.Count and View.CountText with int-string converters. - /// + /// Creates a two-way binding between ViewModel.Count and View.CountText with int-string converters. /// The target view. /// The source view model. /// A reactive binding representing the binding. - public static IReactiveBinding Execute(MyView view, MyViewModel vm) - => view.Bind(vm, x => x.Count, x => x.CountText, count => count.ToString(), int.Parse); + public static IReactiveBinding Execute(MyView view, MyViewModel vm) => + view.Bind(vm, x => x.Count, x => x.CountText, count => count.ToString(), int.Parse); } diff --git a/src/tests/SharedScenarios/Bind/SinglePropertyWithConvertersAndScheduler/MyView.cs b/src/tests/SharedScenarios/Bind/SinglePropertyWithConvertersAndScheduler/MyView.cs index 86ad33a..d8e8bf9 100644 --- a/src/tests/SharedScenarios/Bind/SinglePropertyWithConvertersAndScheduler/MyView.cs +++ b/src/tests/SharedScenarios/Bind/SinglePropertyWithConvertersAndScheduler/MyView.cs @@ -7,14 +7,10 @@ namespace SharedScenarios.Bind.SinglePropertyWithConvertersAndScheduler; -/// -/// Target View with a string property. -/// +/// Target View with a string property. public class MyView : IViewFor, INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _countText = string.Empty; /// @@ -23,9 +19,7 @@ public class MyView : IViewFor, INotifyPropertyChanged /// public object? ViewModel { get; set; } - /// - /// Gets or sets the count text. - /// + /// Gets or sets the count text. public string CountText { get => _countText; diff --git a/src/tests/SharedScenarios/Bind/SinglePropertyWithConvertersAndScheduler/MyViewModel.cs b/src/tests/SharedScenarios/Bind/SinglePropertyWithConvertersAndScheduler/MyViewModel.cs index cc40d12..2b26c17 100644 --- a/src/tests/SharedScenarios/Bind/SinglePropertyWithConvertersAndScheduler/MyViewModel.cs +++ b/src/tests/SharedScenarios/Bind/SinglePropertyWithConvertersAndScheduler/MyViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.Bind.SinglePropertyWithConvertersAndScheduler; -/// -/// Source ViewModel with an integer property. -/// +/// Source ViewModel with an integer property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private int _count; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the count. - /// + /// Gets or sets the count. public int Count { get => _count; diff --git a/src/tests/SharedScenarios/Bind/SinglePropertyWithConvertersAndScheduler/Scenario.cs b/src/tests/SharedScenarios/Bind/SinglePropertyWithConvertersAndScheduler/Scenario.cs index 7a4b109..ea871b1 100644 --- a/src/tests/SharedScenarios/Bind/SinglePropertyWithConvertersAndScheduler/Scenario.cs +++ b/src/tests/SharedScenarios/Bind/SinglePropertyWithConvertersAndScheduler/Scenario.cs @@ -7,14 +7,10 @@ namespace SharedScenarios.Bind.SinglePropertyWithConvertersAndScheduler; -/// -/// Exercises Bind (view-first two-way) with conversion functions and a scheduler. -/// +/// Exercises Bind (view-first two-way) with conversion functions and a scheduler. public static class Scenario { - /// - /// Creates a two-way binding between ViewModel.Count and View.CountText with converters and scheduler. - /// + /// Creates a two-way binding between ViewModel.Count and View.CountText with converters and scheduler. /// The target view. /// The source view model. /// The scheduler to observe on. diff --git a/src/tests/SharedScenarios/Bind/TwoSameTypeBindings/MyView.cs b/src/tests/SharedScenarios/Bind/TwoSameTypeBindings/MyView.cs index 327c7ff..94a94a9 100644 --- a/src/tests/SharedScenarios/Bind/TwoSameTypeBindings/MyView.cs +++ b/src/tests/SharedScenarios/Bind/TwoSameTypeBindings/MyView.cs @@ -7,19 +7,13 @@ namespace SharedScenarios.Bind.TwoSameTypeBindings; -/// -/// Target View with two string properties to test same-type-signature grouping. -/// +/// Target View with two string properties to test same-type-signature grouping. public class MyView : IViewFor, INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _firstNameText = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private string _lastNameText = string.Empty; /// @@ -28,9 +22,7 @@ public class MyView : IViewFor, INotifyPropertyChanged /// public object? ViewModel { get; set; } - /// - /// Gets or sets the first name text. - /// + /// Gets or sets the first name text. public string FirstNameText { get => _firstNameText; @@ -46,9 +38,7 @@ public string FirstNameText } } - /// - /// Gets or sets the last name text. - /// + /// Gets or sets the last name text. public string LastNameText { get => _lastNameText; diff --git a/src/tests/SharedScenarios/Bind/TwoSameTypeBindings/MyViewModel.cs b/src/tests/SharedScenarios/Bind/TwoSameTypeBindings/MyViewModel.cs index 52e7a27..8c937c7 100644 --- a/src/tests/SharedScenarios/Bind/TwoSameTypeBindings/MyViewModel.cs +++ b/src/tests/SharedScenarios/Bind/TwoSameTypeBindings/MyViewModel.cs @@ -6,27 +6,19 @@ namespace SharedScenarios.Bind.TwoSameTypeBindings; -/// -/// Source ViewModel with two string properties to test same-type-signature grouping. -/// +/// Source ViewModel with two string properties to test same-type-signature grouping. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _firstName = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private string _lastName = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the first name. - /// + /// Gets or sets the first name. public string FirstName { get => _firstName; @@ -42,9 +34,7 @@ public string FirstName } } - /// - /// Gets or sets the last name. - /// + /// Gets or sets the last name. public string LastName { get => _lastName; diff --git a/src/tests/SharedScenarios/Bind/TwoSameTypeBindings/Scenario.cs b/src/tests/SharedScenarios/Bind/TwoSameTypeBindings/Scenario.cs index 6c6294f..5bec42c 100644 --- a/src/tests/SharedScenarios/Bind/TwoSameTypeBindings/Scenario.cs +++ b/src/tests/SharedScenarios/Bind/TwoSameTypeBindings/Scenario.cs @@ -20,7 +20,7 @@ public static class Scenario /// The source view model. /// A tuple of bindings. public static (IReactiveBinding first, - IReactiveBinding last) Execute(MyView view, MyViewModel vm) - => (view.Bind(vm, x => x.FirstName, x => x.FirstNameText), + IReactiveBinding last) Execute(MyView view, MyViewModel vm) => + (view.Bind(vm, x => x.FirstName, x => x.FirstNameText), view.Bind(vm, x => x.LastName, x => x.LastNameText)); } diff --git a/src/tests/SharedScenarios/BindCommand/BasicNoParam/MyButton.cs b/src/tests/SharedScenarios/BindCommand/BasicNoParam/MyButton.cs index e881874..aec31e7 100644 --- a/src/tests/SharedScenarios/BindCommand/BasicNoParam/MyButton.cs +++ b/src/tests/SharedScenarios/BindCommand/BasicNoParam/MyButton.cs @@ -6,18 +6,12 @@ namespace SharedScenarios.BindCommand.BasicNoParam; -/// -/// A simple button control with a Click event. -/// +/// A simple button control with a Click event. public class MyButton { - /// - /// Occurs when the button is clicked. - /// + /// Occurs when the button is clicked. public event EventHandler? Click; - /// - /// Simulates a button click. - /// + /// Simulates a button click. public void PerformClick() => Click?.Invoke(this, EventArgs.Empty); } diff --git a/src/tests/SharedScenarios/BindCommand/BasicNoParam/MyView.cs b/src/tests/SharedScenarios/BindCommand/BasicNoParam/MyView.cs index 25ec9fb..d8ba3bf 100644 --- a/src/tests/SharedScenarios/BindCommand/BasicNoParam/MyView.cs +++ b/src/tests/SharedScenarios/BindCommand/BasicNoParam/MyView.cs @@ -7,9 +7,7 @@ namespace SharedScenarios.BindCommand.BasicNoParam; -/// -/// View containing a button control. -/// +/// View containing a button control. #pragma warning disable CS0067 // Event is never used public class MyView : IViewFor, INotifyPropertyChanged { @@ -19,9 +17,7 @@ public class MyView : IViewFor, INotifyPropertyChanged /// public object? ViewModel { get; set; } - /// - /// Gets the save button. - /// + /// Gets the save button. public MyButton SaveButton { get; } = new MyButton(); } #pragma warning restore CS0067 diff --git a/src/tests/SharedScenarios/BindCommand/BasicNoParam/MyViewModel.cs b/src/tests/SharedScenarios/BindCommand/BasicNoParam/MyViewModel.cs index c307a87..06031df 100644 --- a/src/tests/SharedScenarios/BindCommand/BasicNoParam/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindCommand/BasicNoParam/MyViewModel.cs @@ -7,22 +7,16 @@ namespace SharedScenarios.BindCommand.BasicNoParam; -/// -/// ViewModel exposing an ICommand property. -/// +/// ViewModel exposing an ICommand property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private ICommand? _save; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the save command. - /// + /// Gets or sets the save command. public ICommand? Save { get => _save; diff --git a/src/tests/SharedScenarios/BindCommand/BasicNoParam/Scenario.cs b/src/tests/SharedScenarios/BindCommand/BasicNoParam/Scenario.cs index 7100c92..4bac6d8 100644 --- a/src/tests/SharedScenarios/BindCommand/BasicNoParam/Scenario.cs +++ b/src/tests/SharedScenarios/BindCommand/BasicNoParam/Scenario.cs @@ -7,17 +7,13 @@ namespace SharedScenarios.BindCommand.BasicNoParam; -/// -/// Exercises BindCommand with a simple button and no parameter. -/// +/// Exercises BindCommand with a simple button and no parameter. public static class Scenario { - /// - /// Binds the Save command to the SaveButton's Click event. - /// + /// Binds the Save command to the SaveButton's Click event. /// The source view model. /// The target view. /// A disposable representing the binding. - public static IDisposable Execute(MyViewModel vm, MyView view) - => view.BindCommand(vm, x => x.Save, x => x.SaveButton); + public static IDisposable Execute(MyViewModel vm, MyView view) => + view.BindCommand(vm, x => x.Save, x => x.SaveButton); } diff --git a/src/tests/SharedScenarios/BindCommand/CommandProperty/MyView.cs b/src/tests/SharedScenarios/BindCommand/CommandProperty/MyView.cs index f75f67b..11b29fc 100644 --- a/src/tests/SharedScenarios/BindCommand/CommandProperty/MyView.cs +++ b/src/tests/SharedScenarios/BindCommand/CommandProperty/MyView.cs @@ -7,9 +7,7 @@ namespace SharedScenarios.BindCommand.CommandProperty; -/// -/// View containing a WPF-like button with Command property. -/// +/// View containing a WPF-like button with Command property. #pragma warning disable CS0067 // Event is never used public class MyView : IViewFor, INotifyPropertyChanged { @@ -19,9 +17,7 @@ public class MyView : IViewFor, INotifyPropertyChanged /// public object? ViewModel { get; set; } - /// - /// Gets the save button. - /// + /// Gets the save button. public WpfLikeButton SaveButton { get; } = new WpfLikeButton(); } #pragma warning restore CS0067 diff --git a/src/tests/SharedScenarios/BindCommand/CommandProperty/MyViewModel.cs b/src/tests/SharedScenarios/BindCommand/CommandProperty/MyViewModel.cs index e90ce16..ba7b150 100644 --- a/src/tests/SharedScenarios/BindCommand/CommandProperty/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindCommand/CommandProperty/MyViewModel.cs @@ -7,22 +7,16 @@ namespace SharedScenarios.BindCommand.CommandProperty; -/// -/// ViewModel exposing an ICommand property. -/// +/// ViewModel exposing an ICommand property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private ICommand? _save; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the save command. - /// + /// Gets or sets the save command. public ICommand? Save { get => _save; diff --git a/src/tests/SharedScenarios/BindCommand/CommandProperty/Scenario.cs b/src/tests/SharedScenarios/BindCommand/CommandProperty/Scenario.cs index fb9e6ea..214da44 100644 --- a/src/tests/SharedScenarios/BindCommand/CommandProperty/Scenario.cs +++ b/src/tests/SharedScenarios/BindCommand/CommandProperty/Scenario.cs @@ -13,12 +13,10 @@ namespace SharedScenarios.BindCommand.CommandProperty; /// public static class Scenario { - /// - /// Binds the Save command to the SaveButton via Command property. - /// + /// Binds the Save command to the SaveButton via Command property. /// The source view model. /// The target view. /// A disposable representing the binding. - public static IDisposable Execute(MyViewModel vm, MyView view) - => view.BindCommand(vm, x => x.Save, x => x.SaveButton); + public static IDisposable Execute(MyViewModel vm, MyView view) => + view.BindCommand(vm, x => x.Save, x => x.SaveButton); } diff --git a/src/tests/SharedScenarios/BindCommand/CommandProperty/WpfLikeButton.cs b/src/tests/SharedScenarios/BindCommand/CommandProperty/WpfLikeButton.cs index 114309b..4001c23 100644 --- a/src/tests/SharedScenarios/BindCommand/CommandProperty/WpfLikeButton.cs +++ b/src/tests/SharedScenarios/BindCommand/CommandProperty/WpfLikeButton.cs @@ -6,18 +6,12 @@ namespace SharedScenarios.BindCommand.CommandProperty; -/// -/// A WPF-like button with Command and CommandParameter properties. -/// +/// A WPF-like button with Command and CommandParameter properties. public class WpfLikeButton { - /// - /// Gets or sets the command. - /// + /// Gets or sets the command. public ICommand? Command { get; set; } - /// - /// Gets or sets the command parameter. - /// + /// Gets or sets the command parameter. public object? CommandParameter { get; set; } } diff --git a/src/tests/SharedScenarios/BindCommand/CommandPropertyExprParam/MyView.cs b/src/tests/SharedScenarios/BindCommand/CommandPropertyExprParam/MyView.cs index 5077004..0b9c1d7 100644 --- a/src/tests/SharedScenarios/BindCommand/CommandPropertyExprParam/MyView.cs +++ b/src/tests/SharedScenarios/BindCommand/CommandPropertyExprParam/MyView.cs @@ -7,9 +7,7 @@ namespace SharedScenarios.BindCommand.CommandPropertyExprParam; -/// -/// View containing a WPF-like button with Command property. -/// +/// View containing a WPF-like button with Command property. #pragma warning disable CS0067 // Event is never used public class MyView : IViewFor, INotifyPropertyChanged { @@ -19,9 +17,7 @@ public class MyView : IViewFor, INotifyPropertyChanged /// public object? ViewModel { get; set; } - /// - /// Gets the save button. - /// + /// Gets the save button. public WpfLikeButton SaveButton { get; } = new WpfLikeButton(); } #pragma warning restore CS0067 diff --git a/src/tests/SharedScenarios/BindCommand/CommandPropertyExprParam/MyViewModel.cs b/src/tests/SharedScenarios/BindCommand/CommandPropertyExprParam/MyViewModel.cs index 6168626..7114c8f 100644 --- a/src/tests/SharedScenarios/BindCommand/CommandPropertyExprParam/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindCommand/CommandPropertyExprParam/MyViewModel.cs @@ -7,27 +7,19 @@ namespace SharedScenarios.BindCommand.CommandPropertyExprParam; -/// -/// ViewModel exposing an ICommand property and a string parameter property. -/// +/// ViewModel exposing an ICommand property and a string parameter property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private ICommand? _save; - /// - /// The backing field for . - /// + /// The backing field for . private string? _currentItem; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the save command. - /// + /// Gets or sets the save command. public ICommand? Save { get => _save; @@ -43,9 +35,7 @@ public ICommand? Save } } - /// - /// Gets or sets the current item used as command parameter. - /// + /// Gets or sets the current item used as command parameter. public string? CurrentItem { get => _currentItem; diff --git a/src/tests/SharedScenarios/BindCommand/CommandPropertyExprParam/Scenario.cs b/src/tests/SharedScenarios/BindCommand/CommandPropertyExprParam/Scenario.cs index a6b4c04..0c75d03 100644 --- a/src/tests/SharedScenarios/BindCommand/CommandPropertyExprParam/Scenario.cs +++ b/src/tests/SharedScenarios/BindCommand/CommandPropertyExprParam/Scenario.cs @@ -13,12 +13,10 @@ namespace SharedScenarios.BindCommand.CommandPropertyExprParam; /// public static class Scenario { - /// - /// Binds the Save command with an expression parameter. - /// + /// Binds the Save command with an expression parameter. /// The source view model. /// The target view. /// A disposable representing the binding. - public static IDisposable Execute(MyViewModel vm, MyView view) - => view.BindCommand(vm, x => x.Save, x => x.SaveButton, x => x.CurrentItem); + public static IDisposable Execute(MyViewModel vm, MyView view) => + view.BindCommand(vm, x => x.Save, x => x.SaveButton, x => x.CurrentItem); } diff --git a/src/tests/SharedScenarios/BindCommand/CommandPropertyExprParam/WpfLikeButton.cs b/src/tests/SharedScenarios/BindCommand/CommandPropertyExprParam/WpfLikeButton.cs index 781321d..0e69a26 100644 --- a/src/tests/SharedScenarios/BindCommand/CommandPropertyExprParam/WpfLikeButton.cs +++ b/src/tests/SharedScenarios/BindCommand/CommandPropertyExprParam/WpfLikeButton.cs @@ -6,18 +6,12 @@ namespace SharedScenarios.BindCommand.CommandPropertyExprParam; -/// -/// A WPF-like button with Command and CommandParameter properties. -/// +/// A WPF-like button with Command and CommandParameter properties. public class WpfLikeButton { - /// - /// Gets or sets the command. - /// + /// Gets or sets the command. public ICommand? Command { get; set; } - /// - /// Gets or sets the command parameter. - /// + /// Gets or sets the command parameter. public object? CommandParameter { get; set; } } diff --git a/src/tests/SharedScenarios/BindCommand/CommandPropertyObsParam/MyView.cs b/src/tests/SharedScenarios/BindCommand/CommandPropertyObsParam/MyView.cs index cfb933b..f8782f9 100644 --- a/src/tests/SharedScenarios/BindCommand/CommandPropertyObsParam/MyView.cs +++ b/src/tests/SharedScenarios/BindCommand/CommandPropertyObsParam/MyView.cs @@ -7,9 +7,7 @@ namespace SharedScenarios.BindCommand.CommandPropertyObsParam; -/// -/// View containing a WPF-like button with Command property. -/// +/// View containing a WPF-like button with Command property. #pragma warning disable CS0067 // Event is never used public class MyView : IViewFor, INotifyPropertyChanged { @@ -19,9 +17,7 @@ public class MyView : IViewFor, INotifyPropertyChanged /// public object? ViewModel { get; set; } - /// - /// Gets the save button. - /// + /// Gets the save button. public WpfLikeButton SaveButton { get; } = new WpfLikeButton(); } #pragma warning restore CS0067 diff --git a/src/tests/SharedScenarios/BindCommand/CommandPropertyObsParam/MyViewModel.cs b/src/tests/SharedScenarios/BindCommand/CommandPropertyObsParam/MyViewModel.cs index 8010bf1..8a98a3f 100644 --- a/src/tests/SharedScenarios/BindCommand/CommandPropertyObsParam/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindCommand/CommandPropertyObsParam/MyViewModel.cs @@ -7,22 +7,16 @@ namespace SharedScenarios.BindCommand.CommandPropertyObsParam; -/// -/// ViewModel exposing an ICommand property. -/// +/// ViewModel exposing an ICommand property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private ICommand? _save; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the save command. - /// + /// Gets or sets the save command. public ICommand? Save { get => _save; diff --git a/src/tests/SharedScenarios/BindCommand/CommandPropertyObsParam/Scenario.cs b/src/tests/SharedScenarios/BindCommand/CommandPropertyObsParam/Scenario.cs index 9b1976a..4ded05b 100644 --- a/src/tests/SharedScenarios/BindCommand/CommandPropertyObsParam/Scenario.cs +++ b/src/tests/SharedScenarios/BindCommand/CommandPropertyObsParam/Scenario.cs @@ -13,13 +13,11 @@ namespace SharedScenarios.BindCommand.CommandPropertyObsParam; /// public static class Scenario { - /// - /// Binds the Save command with an observable parameter. - /// + /// Binds the Save command with an observable parameter. /// The source view model. /// The target view. /// An observable producing command parameters. /// A disposable representing the binding. - public static IDisposable Execute(MyViewModel vm, MyView view, IObservable parameter) - => view.BindCommand(vm, x => x.Save, x => x.SaveButton, parameter); + public static IDisposable Execute(MyViewModel vm, MyView view, IObservable parameter) => + view.BindCommand(vm, x => x.Save, x => x.SaveButton, parameter); } diff --git a/src/tests/SharedScenarios/BindCommand/CommandPropertyObsParam/WpfLikeButton.cs b/src/tests/SharedScenarios/BindCommand/CommandPropertyObsParam/WpfLikeButton.cs index 9bd38f2..9220d39 100644 --- a/src/tests/SharedScenarios/BindCommand/CommandPropertyObsParam/WpfLikeButton.cs +++ b/src/tests/SharedScenarios/BindCommand/CommandPropertyObsParam/WpfLikeButton.cs @@ -6,18 +6,12 @@ namespace SharedScenarios.BindCommand.CommandPropertyObsParam; -/// -/// A WPF-like button with Command and CommandParameter properties. -/// +/// A WPF-like button with Command and CommandParameter properties. public class WpfLikeButton { - /// - /// Gets or sets the command. - /// + /// Gets or sets the command. public ICommand? Command { get; set; } - /// - /// Gets or sets the command parameter. - /// + /// Gets or sets the command parameter. public object? CommandParameter { get; set; } } diff --git a/src/tests/SharedScenarios/BindCommand/CustomEvent/MyButton.cs b/src/tests/SharedScenarios/BindCommand/CustomEvent/MyButton.cs index 9a378c2..a3d1a3f 100644 --- a/src/tests/SharedScenarios/BindCommand/CustomEvent/MyButton.cs +++ b/src/tests/SharedScenarios/BindCommand/CustomEvent/MyButton.cs @@ -6,18 +6,12 @@ namespace SharedScenarios.BindCommand.CustomEvent; -/// -/// A button control with a custom MouseUp event. -/// +/// A button control with a custom MouseUp event. public class MyButton { - /// - /// Occurs when the mouse button is released. - /// + /// Occurs when the mouse button is released. public event EventHandler? MouseUp; - /// - /// Simulates a mouse up event. - /// + /// Simulates a mouse up event. public void PerformMouseUp() => MouseUp?.Invoke(this, EventArgs.Empty); } diff --git a/src/tests/SharedScenarios/BindCommand/CustomEvent/MyView.cs b/src/tests/SharedScenarios/BindCommand/CustomEvent/MyView.cs index 4ab2db6..e8a55bf 100644 --- a/src/tests/SharedScenarios/BindCommand/CustomEvent/MyView.cs +++ b/src/tests/SharedScenarios/BindCommand/CustomEvent/MyView.cs @@ -7,9 +7,7 @@ namespace SharedScenarios.BindCommand.CustomEvent; -/// -/// View containing a button control. -/// +/// View containing a button control. #pragma warning disable CS0067 // Event is never used public class MyView : IViewFor, INotifyPropertyChanged { @@ -19,9 +17,7 @@ public class MyView : IViewFor, INotifyPropertyChanged /// public object? ViewModel { get; set; } - /// - /// Gets the save button. - /// + /// Gets the save button. public MyButton SaveButton { get; } = new MyButton(); } #pragma warning restore CS0067 diff --git a/src/tests/SharedScenarios/BindCommand/CustomEvent/MyViewModel.cs b/src/tests/SharedScenarios/BindCommand/CustomEvent/MyViewModel.cs index 085a49c..d95fcc6 100644 --- a/src/tests/SharedScenarios/BindCommand/CustomEvent/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindCommand/CustomEvent/MyViewModel.cs @@ -7,22 +7,16 @@ namespace SharedScenarios.BindCommand.CustomEvent; -/// -/// ViewModel exposing an ICommand property. -/// +/// ViewModel exposing an ICommand property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private ICommand? _save; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the save command. - /// + /// Gets or sets the save command. public ICommand? Save { get => _save; diff --git a/src/tests/SharedScenarios/BindCommand/CustomEvent/Scenario.cs b/src/tests/SharedScenarios/BindCommand/CustomEvent/Scenario.cs index 331414f..4aaee5e 100644 --- a/src/tests/SharedScenarios/BindCommand/CustomEvent/Scenario.cs +++ b/src/tests/SharedScenarios/BindCommand/CustomEvent/Scenario.cs @@ -7,17 +7,13 @@ namespace SharedScenarios.BindCommand.CustomEvent; -/// -/// Exercises BindCommand with an explicit toEvent parameter. -/// +/// Exercises BindCommand with an explicit toEvent parameter. public static class Scenario { - /// - /// Binds the Save command to the SaveButton's MouseUp event via explicit toEvent. - /// + /// Binds the Save command to the SaveButton's MouseUp event via explicit toEvent. /// The source view model. /// The target view. /// A disposable representing the binding. - public static IDisposable Execute(MyViewModel vm, MyView view) - => view.BindCommand(vm, x => x.Save, x => x.SaveButton, "MouseUp"); + public static IDisposable Execute(MyViewModel vm, MyView view) => + view.BindCommand(vm, x => x.Save, x => x.SaveButton, "MouseUp"); } diff --git a/src/tests/SharedScenarios/BindCommand/DeepCommandPath/ChildViewModel.cs b/src/tests/SharedScenarios/BindCommand/DeepCommandPath/ChildViewModel.cs index 58e759c..aa2ab9b 100644 --- a/src/tests/SharedScenarios/BindCommand/DeepCommandPath/ChildViewModel.cs +++ b/src/tests/SharedScenarios/BindCommand/DeepCommandPath/ChildViewModel.cs @@ -7,22 +7,16 @@ namespace SharedScenarios.BindCommand.DeepCommandPath; -/// -/// Child ViewModel that owns the command. -/// +/// Child ViewModel that owns the command. public class ChildViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private ICommand? _saveCommand; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the save command. - /// + /// Gets or sets the save command. public ICommand? SaveCommand { get => _saveCommand; diff --git a/src/tests/SharedScenarios/BindCommand/DeepCommandPath/MyButton.cs b/src/tests/SharedScenarios/BindCommand/DeepCommandPath/MyButton.cs index 65aa6a0..9349a03 100644 --- a/src/tests/SharedScenarios/BindCommand/DeepCommandPath/MyButton.cs +++ b/src/tests/SharedScenarios/BindCommand/DeepCommandPath/MyButton.cs @@ -6,18 +6,12 @@ namespace SharedScenarios.BindCommand.DeepCommandPath; -/// -/// A simple button control with a Click event. -/// +/// A simple button control with a Click event. public class MyButton { - /// - /// Occurs when the button is clicked. - /// + /// Occurs when the button is clicked. public event EventHandler? Click; - /// - /// Simulates a button click. - /// + /// Simulates a button click. public void PerformClick() => Click?.Invoke(this, EventArgs.Empty); } diff --git a/src/tests/SharedScenarios/BindCommand/DeepCommandPath/MyView.cs b/src/tests/SharedScenarios/BindCommand/DeepCommandPath/MyView.cs index bc9b13f..bb6d21e 100644 --- a/src/tests/SharedScenarios/BindCommand/DeepCommandPath/MyView.cs +++ b/src/tests/SharedScenarios/BindCommand/DeepCommandPath/MyView.cs @@ -7,9 +7,7 @@ namespace SharedScenarios.BindCommand.DeepCommandPath; -/// -/// View containing a button control. -/// +/// View containing a button control. #pragma warning disable CS0067 // Event is never used public class MyView : IViewFor, INotifyPropertyChanged { @@ -19,9 +17,7 @@ public class MyView : IViewFor, INotifyPropertyChanged /// public object? ViewModel { get; set; } - /// - /// Gets the save button. - /// + /// Gets the save button. public MyButton SaveButton { get; } = new MyButton(); } #pragma warning restore CS0067 diff --git a/src/tests/SharedScenarios/BindCommand/DeepCommandPath/MyViewModel.cs b/src/tests/SharedScenarios/BindCommand/DeepCommandPath/MyViewModel.cs index 5f0c63c..f1886bc 100644 --- a/src/tests/SharedScenarios/BindCommand/DeepCommandPath/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindCommand/DeepCommandPath/MyViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.BindCommand.DeepCommandPath; -/// -/// Parent ViewModel containing a child with the command. -/// +/// Parent ViewModel containing a child with the command. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private ChildViewModel? _child; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the child view model. - /// + /// Gets or sets the child view model. public ChildViewModel? Child { get => _child; diff --git a/src/tests/SharedScenarios/BindCommand/DeepCommandPath/Scenario.cs b/src/tests/SharedScenarios/BindCommand/DeepCommandPath/Scenario.cs index 4c8ebaf..3dc00e9 100644 --- a/src/tests/SharedScenarios/BindCommand/DeepCommandPath/Scenario.cs +++ b/src/tests/SharedScenarios/BindCommand/DeepCommandPath/Scenario.cs @@ -7,17 +7,13 @@ namespace SharedScenarios.BindCommand.DeepCommandPath; -/// -/// Exercises BindCommand with a nested command property path. -/// +/// Exercises BindCommand with a nested command property path. public static class Scenario { - /// - /// Binds the Child.SaveCommand to the SaveButton's Click event. - /// + /// Binds the Child.SaveCommand to the SaveButton's Click event. /// The source view model. /// The target view. /// A disposable representing the binding. - public static IDisposable Execute(MyViewModel vm, MyView view) - => view.BindCommand(vm, x => x.Child!.SaveCommand, x => x.SaveButton); + public static IDisposable Execute(MyViewModel vm, MyView view) => + view.BindCommand(vm, x => x.Child!.SaveCommand, x => x.SaveButton); } diff --git a/src/tests/SharedScenarios/BindCommand/EventEnabled/MyView.cs b/src/tests/SharedScenarios/BindCommand/EventEnabled/MyView.cs index 2b313a7..b379724 100644 --- a/src/tests/SharedScenarios/BindCommand/EventEnabled/MyView.cs +++ b/src/tests/SharedScenarios/BindCommand/EventEnabled/MyView.cs @@ -7,9 +7,7 @@ namespace SharedScenarios.BindCommand.EventEnabled; -/// -/// View containing a WinForms-like button with Click+Enabled. -/// +/// View containing a WinForms-like button with Click+Enabled. #pragma warning disable CS0067 // Event is never used public class MyView : IViewFor, INotifyPropertyChanged { @@ -19,9 +17,7 @@ public class MyView : IViewFor, INotifyPropertyChanged /// public object? ViewModel { get; set; } - /// - /// Gets the save button. - /// + /// Gets the save button. public WinFormsLikeButton SaveButton { get; } = new WinFormsLikeButton(); } #pragma warning restore CS0067 diff --git a/src/tests/SharedScenarios/BindCommand/EventEnabled/MyViewModel.cs b/src/tests/SharedScenarios/BindCommand/EventEnabled/MyViewModel.cs index 98e8c3e..9e92be1 100644 --- a/src/tests/SharedScenarios/BindCommand/EventEnabled/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindCommand/EventEnabled/MyViewModel.cs @@ -7,22 +7,16 @@ namespace SharedScenarios.BindCommand.EventEnabled; -/// -/// ViewModel exposing an ICommand property. -/// +/// ViewModel exposing an ICommand property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private ICommand? _save; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the save command. - /// + /// Gets or sets the save command. public ICommand? Save { get => _save; diff --git a/src/tests/SharedScenarios/BindCommand/EventEnabled/Scenario.cs b/src/tests/SharedScenarios/BindCommand/EventEnabled/Scenario.cs index 3e7ceae..8675527 100644 --- a/src/tests/SharedScenarios/BindCommand/EventEnabled/Scenario.cs +++ b/src/tests/SharedScenarios/BindCommand/EventEnabled/Scenario.cs @@ -13,12 +13,10 @@ namespace SharedScenarios.BindCommand.EventEnabled; /// public static class Scenario { - /// - /// Binds the Save command to the SaveButton via event+Enabled synchronization. - /// + /// Binds the Save command to the SaveButton via event+Enabled synchronization. /// The source view model. /// The target view. /// A disposable representing the binding. - public static IDisposable Execute(MyViewModel vm, MyView view) - => view.BindCommand(vm, x => x.Save, x => x.SaveButton); + public static IDisposable Execute(MyViewModel vm, MyView view) => + view.BindCommand(vm, x => x.Save, x => x.SaveButton); } diff --git a/src/tests/SharedScenarios/BindCommand/EventEnabled/WinFormsLikeButton.cs b/src/tests/SharedScenarios/BindCommand/EventEnabled/WinFormsLikeButton.cs index 1abb429..8abdbf4 100644 --- a/src/tests/SharedScenarios/BindCommand/EventEnabled/WinFormsLikeButton.cs +++ b/src/tests/SharedScenarios/BindCommand/EventEnabled/WinFormsLikeButton.cs @@ -6,23 +6,15 @@ namespace SharedScenarios.BindCommand.EventEnabled; -/// -/// A WinForms-like button with Click event and Enabled property but no Command property. -/// +/// A WinForms-like button with Click event and Enabled property but no Command property. public class WinFormsLikeButton { - /// - /// Occurs when the button is clicked. - /// + /// Occurs when the button is clicked. public event EventHandler? Click; - /// - /// Gets or sets a value indicating whether the button is enabled. - /// + /// Gets or sets a value indicating whether the button is enabled. public bool Enabled { get; set; } - /// - /// Simulates a button click. - /// + /// Simulates a button click. public void PerformClick() => Click?.Invoke(this, EventArgs.Empty); } diff --git a/src/tests/SharedScenarios/BindCommand/EventEnabledExprParam/MyView.cs b/src/tests/SharedScenarios/BindCommand/EventEnabledExprParam/MyView.cs index 15ad537..6a238a6 100644 --- a/src/tests/SharedScenarios/BindCommand/EventEnabledExprParam/MyView.cs +++ b/src/tests/SharedScenarios/BindCommand/EventEnabledExprParam/MyView.cs @@ -7,9 +7,7 @@ namespace SharedScenarios.BindCommand.EventEnabledExprParam; -/// -/// View containing a WinForms-like button with Click+Enabled. -/// +/// View containing a WinForms-like button with Click+Enabled. #pragma warning disable CS0067 // Event is never used public class MyView : IViewFor, INotifyPropertyChanged { @@ -19,9 +17,7 @@ public class MyView : IViewFor, INotifyPropertyChanged /// public object? ViewModel { get; set; } - /// - /// Gets the save button. - /// + /// Gets the save button. public WinFormsLikeButton SaveButton { get; } = new WinFormsLikeButton(); } #pragma warning restore CS0067 diff --git a/src/tests/SharedScenarios/BindCommand/EventEnabledExprParam/MyViewModel.cs b/src/tests/SharedScenarios/BindCommand/EventEnabledExprParam/MyViewModel.cs index 67aa925..1404846 100644 --- a/src/tests/SharedScenarios/BindCommand/EventEnabledExprParam/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindCommand/EventEnabledExprParam/MyViewModel.cs @@ -7,27 +7,19 @@ namespace SharedScenarios.BindCommand.EventEnabledExprParam; -/// -/// ViewModel exposing an ICommand property and a string parameter property. -/// +/// ViewModel exposing an ICommand property and a string parameter property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private ICommand? _save; - /// - /// The backing field for . - /// + /// The backing field for . private string? _currentItem; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the save command. - /// + /// Gets or sets the save command. public ICommand? Save { get => _save; @@ -43,9 +35,7 @@ public ICommand? Save } } - /// - /// Gets or sets the current item used as command parameter. - /// + /// Gets or sets the current item used as command parameter. public string? CurrentItem { get => _currentItem; diff --git a/src/tests/SharedScenarios/BindCommand/EventEnabledExprParam/Scenario.cs b/src/tests/SharedScenarios/BindCommand/EventEnabledExprParam/Scenario.cs index 278a158..0238a1f 100644 --- a/src/tests/SharedScenarios/BindCommand/EventEnabledExprParam/Scenario.cs +++ b/src/tests/SharedScenarios/BindCommand/EventEnabledExprParam/Scenario.cs @@ -13,12 +13,10 @@ namespace SharedScenarios.BindCommand.EventEnabledExprParam; /// public static class Scenario { - /// - /// Binds the Save command with an expression parameter. - /// + /// Binds the Save command with an expression parameter. /// The source view model. /// The target view. /// A disposable representing the binding. - public static IDisposable Execute(MyViewModel vm, MyView view) - => view.BindCommand(vm, x => x.Save, x => x.SaveButton, x => x.CurrentItem); + public static IDisposable Execute(MyViewModel vm, MyView view) => + view.BindCommand(vm, x => x.Save, x => x.SaveButton, x => x.CurrentItem); } diff --git a/src/tests/SharedScenarios/BindCommand/EventEnabledExprParam/WinFormsLikeButton.cs b/src/tests/SharedScenarios/BindCommand/EventEnabledExprParam/WinFormsLikeButton.cs index 7efe62f..9dfa1ac 100644 --- a/src/tests/SharedScenarios/BindCommand/EventEnabledExprParam/WinFormsLikeButton.cs +++ b/src/tests/SharedScenarios/BindCommand/EventEnabledExprParam/WinFormsLikeButton.cs @@ -6,23 +6,15 @@ namespace SharedScenarios.BindCommand.EventEnabledExprParam; -/// -/// A WinForms-like button with Click event and Enabled property but no Command property. -/// +/// A WinForms-like button with Click event and Enabled property but no Command property. public class WinFormsLikeButton { - /// - /// Occurs when the button is clicked. - /// + /// Occurs when the button is clicked. public event EventHandler? Click; - /// - /// Gets or sets a value indicating whether the button is enabled. - /// + /// Gets or sets a value indicating whether the button is enabled. public bool Enabled { get; set; } - /// - /// Simulates a button click. - /// + /// Simulates a button click. public void PerformClick() => Click?.Invoke(this, EventArgs.Empty); } diff --git a/src/tests/SharedScenarios/BindCommand/EventEnabledObsParam/MyView.cs b/src/tests/SharedScenarios/BindCommand/EventEnabledObsParam/MyView.cs index 74694bf..cc52848 100644 --- a/src/tests/SharedScenarios/BindCommand/EventEnabledObsParam/MyView.cs +++ b/src/tests/SharedScenarios/BindCommand/EventEnabledObsParam/MyView.cs @@ -7,9 +7,7 @@ namespace SharedScenarios.BindCommand.EventEnabledObsParam; -/// -/// View containing a WinForms-like button with Click+Enabled. -/// +/// View containing a WinForms-like button with Click+Enabled. #pragma warning disable CS0067 // Event is never used public class MyView : IViewFor, INotifyPropertyChanged { @@ -19,9 +17,7 @@ public class MyView : IViewFor, INotifyPropertyChanged /// public object? ViewModel { get; set; } - /// - /// Gets the save button. - /// + /// Gets the save button. public WinFormsLikeButton SaveButton { get; } = new WinFormsLikeButton(); } #pragma warning restore CS0067 diff --git a/src/tests/SharedScenarios/BindCommand/EventEnabledObsParam/MyViewModel.cs b/src/tests/SharedScenarios/BindCommand/EventEnabledObsParam/MyViewModel.cs index 2df84b1..f37583d 100644 --- a/src/tests/SharedScenarios/BindCommand/EventEnabledObsParam/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindCommand/EventEnabledObsParam/MyViewModel.cs @@ -7,22 +7,16 @@ namespace SharedScenarios.BindCommand.EventEnabledObsParam; -/// -/// ViewModel exposing an ICommand property. -/// +/// ViewModel exposing an ICommand property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private ICommand? _save; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the save command. - /// + /// Gets or sets the save command. public ICommand? Save { get => _save; diff --git a/src/tests/SharedScenarios/BindCommand/EventEnabledObsParam/Scenario.cs b/src/tests/SharedScenarios/BindCommand/EventEnabledObsParam/Scenario.cs index f21472a..0a1b004 100644 --- a/src/tests/SharedScenarios/BindCommand/EventEnabledObsParam/Scenario.cs +++ b/src/tests/SharedScenarios/BindCommand/EventEnabledObsParam/Scenario.cs @@ -13,13 +13,11 @@ namespace SharedScenarios.BindCommand.EventEnabledObsParam; /// public static class Scenario { - /// - /// Binds the Save command with an observable parameter. - /// + /// Binds the Save command with an observable parameter. /// The source view model. /// The target view. /// An observable producing command parameters. /// A disposable representing the binding. - public static IDisposable Execute(MyViewModel vm, MyView view, IObservable parameter) - => view.BindCommand(vm, x => x.Save, x => x.SaveButton, parameter); + public static IDisposable Execute(MyViewModel vm, MyView view, IObservable parameter) => + view.BindCommand(vm, x => x.Save, x => x.SaveButton, parameter); } diff --git a/src/tests/SharedScenarios/BindCommand/EventEnabledObsParam/WinFormsLikeButton.cs b/src/tests/SharedScenarios/BindCommand/EventEnabledObsParam/WinFormsLikeButton.cs index 859da6a..9b9d68b 100644 --- a/src/tests/SharedScenarios/BindCommand/EventEnabledObsParam/WinFormsLikeButton.cs +++ b/src/tests/SharedScenarios/BindCommand/EventEnabledObsParam/WinFormsLikeButton.cs @@ -6,23 +6,15 @@ namespace SharedScenarios.BindCommand.EventEnabledObsParam; -/// -/// A WinForms-like button with Click event and Enabled property but no Command property. -/// +/// A WinForms-like button with Click event and Enabled property but no Command property. public class WinFormsLikeButton { - /// - /// Occurs when the button is clicked. - /// + /// Occurs when the button is clicked. public event EventHandler? Click; - /// - /// Gets or sets a value indicating whether the button is enabled. - /// + /// Gets or sets a value indicating whether the button is enabled. public bool Enabled { get; set; } - /// - /// Simulates a button click. - /// + /// Simulates a button click. public void PerformClick() => Click?.Invoke(this, EventArgs.Empty); } diff --git a/src/tests/SharedScenarios/BindCommand/ExpressionParam/MyButton.cs b/src/tests/SharedScenarios/BindCommand/ExpressionParam/MyButton.cs index 877171e..b0f80b6 100644 --- a/src/tests/SharedScenarios/BindCommand/ExpressionParam/MyButton.cs +++ b/src/tests/SharedScenarios/BindCommand/ExpressionParam/MyButton.cs @@ -6,18 +6,12 @@ namespace SharedScenarios.BindCommand.ExpressionParam; -/// -/// A simple button control with a Click event. -/// +/// A simple button control with a Click event. public class MyButton { - /// - /// Occurs when the button is clicked. - /// + /// Occurs when the button is clicked. public event EventHandler? Click; - /// - /// Simulates a button click. - /// + /// Simulates a button click. public void PerformClick() => Click?.Invoke(this, EventArgs.Empty); } diff --git a/src/tests/SharedScenarios/BindCommand/ExpressionParam/MyView.cs b/src/tests/SharedScenarios/BindCommand/ExpressionParam/MyView.cs index 9bd4344..0621f01 100644 --- a/src/tests/SharedScenarios/BindCommand/ExpressionParam/MyView.cs +++ b/src/tests/SharedScenarios/BindCommand/ExpressionParam/MyView.cs @@ -7,9 +7,7 @@ namespace SharedScenarios.BindCommand.ExpressionParam; -/// -/// View containing a button control. -/// +/// View containing a button control. #pragma warning disable CS0067 // Event is never used public class MyView : IViewFor, INotifyPropertyChanged { @@ -19,9 +17,7 @@ public class MyView : IViewFor, INotifyPropertyChanged /// public object? ViewModel { get; set; } - /// - /// Gets the save button. - /// + /// Gets the save button. public MyButton SaveButton { get; } = new MyButton(); } #pragma warning restore CS0067 diff --git a/src/tests/SharedScenarios/BindCommand/ExpressionParam/MyViewModel.cs b/src/tests/SharedScenarios/BindCommand/ExpressionParam/MyViewModel.cs index 7355159..c214af2 100644 --- a/src/tests/SharedScenarios/BindCommand/ExpressionParam/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindCommand/ExpressionParam/MyViewModel.cs @@ -7,27 +7,19 @@ namespace SharedScenarios.BindCommand.ExpressionParam; -/// -/// ViewModel exposing an ICommand property and a string parameter property. -/// +/// ViewModel exposing an ICommand property and a string parameter property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private ICommand? _save; - /// - /// The backing field for . - /// + /// The backing field for . private string? _currentItem; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the save command. - /// + /// Gets or sets the save command. public ICommand? Save { get => _save; @@ -43,9 +35,7 @@ public ICommand? Save } } - /// - /// Gets or sets the current item used as command parameter. - /// + /// Gets or sets the current item used as command parameter. public string? CurrentItem { get => _currentItem; diff --git a/src/tests/SharedScenarios/BindCommand/ExpressionParam/Scenario.cs b/src/tests/SharedScenarios/BindCommand/ExpressionParam/Scenario.cs index b8690c1..3d1e10d 100644 --- a/src/tests/SharedScenarios/BindCommand/ExpressionParam/Scenario.cs +++ b/src/tests/SharedScenarios/BindCommand/ExpressionParam/Scenario.cs @@ -7,17 +7,13 @@ namespace SharedScenarios.BindCommand.ExpressionParam; -/// -/// Exercises BindCommand with an expression-based parameter. -/// +/// Exercises BindCommand with an expression-based parameter. public static class Scenario { - /// - /// Binds the Save command to the SaveButton's Click event with an expression parameter. - /// + /// Binds the Save command to the SaveButton's Click event with an expression parameter. /// The source view model. /// The target view. /// A disposable representing the binding. - public static IDisposable Execute(MyViewModel vm, MyView view) - => view.BindCommand(vm, x => x.Save, x => x.SaveButton, x => x.CurrentItem); + public static IDisposable Execute(MyViewModel vm, MyView view) => + view.BindCommand(vm, x => x.Save, x => x.SaveButton, x => x.CurrentItem); } diff --git a/src/tests/SharedScenarios/BindCommand/NoEvent/MyView.cs b/src/tests/SharedScenarios/BindCommand/NoEvent/MyView.cs index 68ca102..e553bc0 100644 --- a/src/tests/SharedScenarios/BindCommand/NoEvent/MyView.cs +++ b/src/tests/SharedScenarios/BindCommand/NoEvent/MyView.cs @@ -7,9 +7,7 @@ namespace SharedScenarios.BindCommand.NoEvent; -/// -/// View containing a plain control with no events. -/// +/// View containing a plain control with no events. #pragma warning disable CS0067 // Event is never used public class MyView : IViewFor, INotifyPropertyChanged { @@ -19,9 +17,7 @@ public class MyView : IViewFor, INotifyPropertyChanged /// public object? ViewModel { get; set; } - /// - /// Gets the plain control (no Click event). - /// + /// Gets the plain control (no Click event). public PlainControl Label { get; } = new PlainControl(); } #pragma warning restore CS0067 diff --git a/src/tests/SharedScenarios/BindCommand/NoEvent/MyViewModel.cs b/src/tests/SharedScenarios/BindCommand/NoEvent/MyViewModel.cs index e2d2cfc..b8aec2b 100644 --- a/src/tests/SharedScenarios/BindCommand/NoEvent/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindCommand/NoEvent/MyViewModel.cs @@ -7,22 +7,16 @@ namespace SharedScenarios.BindCommand.NoEvent; -/// -/// ViewModel exposing an ICommand property. -/// +/// ViewModel exposing an ICommand property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private ICommand? _save; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the save command. - /// + /// Gets or sets the save command. public ICommand? Save { get => _save; diff --git a/src/tests/SharedScenarios/BindCommand/NoEvent/PlainControl.cs b/src/tests/SharedScenarios/BindCommand/NoEvent/PlainControl.cs index 00c07ed..2fade04 100644 --- a/src/tests/SharedScenarios/BindCommand/NoEvent/PlainControl.cs +++ b/src/tests/SharedScenarios/BindCommand/NoEvent/PlainControl.cs @@ -4,13 +4,9 @@ namespace SharedScenarios.BindCommand.NoEvent; -/// -/// A control with no Click, TouchUpInside, MouseUp, or Pressed event. -/// +/// A control with no Click, TouchUpInside, MouseUp, or Pressed event. public class PlainControl { - /// - /// Gets or sets the text content. - /// + /// Gets or sets the text content. public string Text { get; set; } = string.Empty; } diff --git a/src/tests/SharedScenarios/BindCommand/NoEvent/Scenario.cs b/src/tests/SharedScenarios/BindCommand/NoEvent/Scenario.cs index d3f8426..89122ca 100644 --- a/src/tests/SharedScenarios/BindCommand/NoEvent/Scenario.cs +++ b/src/tests/SharedScenarios/BindCommand/NoEvent/Scenario.cs @@ -7,17 +7,13 @@ namespace SharedScenarios.BindCommand.NoEvent; -/// -/// Exercises BindCommand with a control that has no default event. -/// +/// Exercises BindCommand with a control that has no default event. public static class Scenario { - /// - /// Binds the Save command to a control with no Click event. - /// + /// Binds the Save command to a control with no Click event. /// The source view model. /// The target view. /// A disposable representing the binding. - public static IDisposable Execute(MyViewModel vm, MyView view) - => view.BindCommand(vm, x => x.Save, x => x.Label); + public static IDisposable Execute(MyViewModel vm, MyView view) => + view.BindCommand(vm, x => x.Save, x => x.Label); } diff --git a/src/tests/SharedScenarios/BindCommand/ObservableParam/MyButton.cs b/src/tests/SharedScenarios/BindCommand/ObservableParam/MyButton.cs index fdb9d40..98cde80 100644 --- a/src/tests/SharedScenarios/BindCommand/ObservableParam/MyButton.cs +++ b/src/tests/SharedScenarios/BindCommand/ObservableParam/MyButton.cs @@ -6,18 +6,12 @@ namespace SharedScenarios.BindCommand.ObservableParam; -/// -/// A simple button control with a Click event. -/// +/// A simple button control with a Click event. public class MyButton { - /// - /// Occurs when the button is clicked. - /// + /// Occurs when the button is clicked. public event EventHandler? Click; - /// - /// Simulates a button click. - /// + /// Simulates a button click. public void PerformClick() => Click?.Invoke(this, EventArgs.Empty); } diff --git a/src/tests/SharedScenarios/BindCommand/ObservableParam/MyView.cs b/src/tests/SharedScenarios/BindCommand/ObservableParam/MyView.cs index ce82524..76bef3b 100644 --- a/src/tests/SharedScenarios/BindCommand/ObservableParam/MyView.cs +++ b/src/tests/SharedScenarios/BindCommand/ObservableParam/MyView.cs @@ -7,9 +7,7 @@ namespace SharedScenarios.BindCommand.ObservableParam; -/// -/// View containing a button control. -/// +/// View containing a button control. #pragma warning disable CS0067 // Event is never used public class MyView : IViewFor, INotifyPropertyChanged { @@ -19,9 +17,7 @@ public class MyView : IViewFor, INotifyPropertyChanged /// public object? ViewModel { get; set; } - /// - /// Gets the save button. - /// + /// Gets the save button. public MyButton SaveButton { get; } = new MyButton(); } #pragma warning restore CS0067 diff --git a/src/tests/SharedScenarios/BindCommand/ObservableParam/MyViewModel.cs b/src/tests/SharedScenarios/BindCommand/ObservableParam/MyViewModel.cs index 48e30d7..6de41ef 100644 --- a/src/tests/SharedScenarios/BindCommand/ObservableParam/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindCommand/ObservableParam/MyViewModel.cs @@ -7,22 +7,16 @@ namespace SharedScenarios.BindCommand.ObservableParam; -/// -/// ViewModel exposing an ICommand property. -/// +/// ViewModel exposing an ICommand property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private ICommand? _save; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the save command. - /// + /// Gets or sets the save command. public ICommand? Save { get => _save; diff --git a/src/tests/SharedScenarios/BindCommand/ObservableParam/Scenario.cs b/src/tests/SharedScenarios/BindCommand/ObservableParam/Scenario.cs index 430139d..bbda98b 100644 --- a/src/tests/SharedScenarios/BindCommand/ObservableParam/Scenario.cs +++ b/src/tests/SharedScenarios/BindCommand/ObservableParam/Scenario.cs @@ -7,18 +7,14 @@ namespace SharedScenarios.BindCommand.ObservableParam; -/// -/// Exercises BindCommand with an IObservable parameter. -/// +/// Exercises BindCommand with an IObservable parameter. public static class Scenario { - /// - /// Binds the Save command to the SaveButton's Click event with an observable parameter. - /// + /// Binds the Save command to the SaveButton's Click event with an observable parameter. /// The source view model. /// The target view. /// An observable producing command parameters. /// A disposable representing the binding. - public static IDisposable Execute(MyViewModel vm, MyView view, IObservable parameter) - => view.BindCommand(vm, x => x.Save, x => x.SaveButton, parameter); + public static IDisposable Execute(MyViewModel vm, MyView view, IObservable parameter) => + view.BindCommand(vm, x => x.Save, x => x.SaveButton, parameter); } diff --git a/src/tests/SharedScenarios/BindInteraction/DeepPropertyPath/ChildViewModel.cs b/src/tests/SharedScenarios/BindInteraction/DeepPropertyPath/ChildViewModel.cs index 2a1dc91..bd779ed 100644 --- a/src/tests/SharedScenarios/BindInteraction/DeepPropertyPath/ChildViewModel.cs +++ b/src/tests/SharedScenarios/BindInteraction/DeepPropertyPath/ChildViewModel.cs @@ -7,22 +7,16 @@ namespace SharedScenarios.BindInteraction.DeepPropertyPath; -/// -/// Child ViewModel holding the interaction. -/// +/// Child ViewModel holding the interaction. public class ChildViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private Interaction _confirm = new Interaction(); /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the confirmation interaction. - /// + /// Gets or sets the confirmation interaction. public Interaction Confirm { get => _confirm; diff --git a/src/tests/SharedScenarios/BindInteraction/DeepPropertyPath/MyView.cs b/src/tests/SharedScenarios/BindInteraction/DeepPropertyPath/MyView.cs index 54692f4..79513b6 100644 --- a/src/tests/SharedScenarios/BindInteraction/DeepPropertyPath/MyView.cs +++ b/src/tests/SharedScenarios/BindInteraction/DeepPropertyPath/MyView.cs @@ -7,9 +7,7 @@ namespace SharedScenarios.BindInteraction.DeepPropertyPath; -/// -/// View that binds an interaction handler. -/// +/// View that binds an interaction handler. #pragma warning disable CS0067 // Event is never used public class MyView : IViewFor, INotifyPropertyChanged { diff --git a/src/tests/SharedScenarios/BindInteraction/DeepPropertyPath/MyViewModel.cs b/src/tests/SharedScenarios/BindInteraction/DeepPropertyPath/MyViewModel.cs index 9f710db..52c3ef3 100644 --- a/src/tests/SharedScenarios/BindInteraction/DeepPropertyPath/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindInteraction/DeepPropertyPath/MyViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.BindInteraction.DeepPropertyPath; -/// -/// ViewModel with a nested child that holds the interaction. -/// +/// ViewModel with a nested child that holds the interaction. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private ChildViewModel? _child; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the child view model. - /// + /// Gets or sets the child view model. public ChildViewModel? Child { get => _child; diff --git a/src/tests/SharedScenarios/BindInteraction/DeepPropertyPath/Scenario.cs b/src/tests/SharedScenarios/BindInteraction/DeepPropertyPath/Scenario.cs index 59a32a2..d23d1b3 100644 --- a/src/tests/SharedScenarios/BindInteraction/DeepPropertyPath/Scenario.cs +++ b/src/tests/SharedScenarios/BindInteraction/DeepPropertyPath/Scenario.cs @@ -8,19 +8,15 @@ namespace SharedScenarios.BindInteraction.DeepPropertyPath; -/// -/// Exercises BindInteraction with a deep property path (Child.Confirm). -/// +/// Exercises BindInteraction with a deep property path (Child.Confirm). public static class Scenario { - /// - /// Binds a task handler to the ViewModel's Child.Confirm interaction. - /// + /// Binds a task handler to the ViewModel's Child.Confirm interaction. /// The source view model. /// The target view. /// A disposable representing the binding. - public static IDisposable Execute(MyViewModel vm, MyView view) - => view.BindInteraction(vm, x => x.Child!.Confirm, ctx => + public static IDisposable Execute(MyViewModel vm, MyView view) => + view.BindInteraction(vm, x => x.Child!.Confirm, ctx => { ctx.SetOutput(true); return Task.CompletedTask; diff --git a/src/tests/SharedScenarios/BindInteraction/NonINPCViewModel/MyView.cs b/src/tests/SharedScenarios/BindInteraction/NonINPCViewModel/MyView.cs index 5b8cc31..0dcd874 100644 --- a/src/tests/SharedScenarios/BindInteraction/NonINPCViewModel/MyView.cs +++ b/src/tests/SharedScenarios/BindInteraction/NonINPCViewModel/MyView.cs @@ -7,9 +7,7 @@ namespace SharedScenarios.BindInteraction.NonINPCViewModel; -/// -/// View that binds an interaction handler. -/// +/// View that binds an interaction handler. #pragma warning disable CS0067 // Event is never used public class MyView : IViewFor, INotifyPropertyChanged { diff --git a/src/tests/SharedScenarios/BindInteraction/NonINPCViewModel/MyViewModel.cs b/src/tests/SharedScenarios/BindInteraction/NonINPCViewModel/MyViewModel.cs index 91be7b3..2c6eede 100644 --- a/src/tests/SharedScenarios/BindInteraction/NonINPCViewModel/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindInteraction/NonINPCViewModel/MyViewModel.cs @@ -12,8 +12,6 @@ namespace SharedScenarios.BindInteraction.NonINPCViewModel; /// public class MyViewModel { - /// - /// Gets the confirmation interaction. - /// + /// Gets the confirmation interaction. public Interaction Confirm { get; } = new Interaction(); } diff --git a/src/tests/SharedScenarios/BindInteraction/NonINPCViewModel/Scenario.cs b/src/tests/SharedScenarios/BindInteraction/NonINPCViewModel/Scenario.cs index cb51238..92c4314 100644 --- a/src/tests/SharedScenarios/BindInteraction/NonINPCViewModel/Scenario.cs +++ b/src/tests/SharedScenarios/BindInteraction/NonINPCViewModel/Scenario.cs @@ -8,19 +8,15 @@ namespace SharedScenarios.BindInteraction.NonINPCViewModel; -/// -/// Exercises BindInteraction with a ViewModel that does not implement INPC. -/// +/// Exercises BindInteraction with a ViewModel that does not implement INPC. public static class Scenario { - /// - /// Binds a task handler to the ViewModel's Confirm interaction. - /// + /// Binds a task handler to the ViewModel's Confirm interaction. /// The source view model. /// The target view. /// A disposable representing the binding. - public static IDisposable Execute(MyViewModel vm, MyView view) - => view.BindInteraction(vm, x => x.Confirm, ctx => + public static IDisposable Execute(MyViewModel vm, MyView view) => + view.BindInteraction(vm, x => x.Confirm, ctx => { ctx.SetOutput(true); return Task.CompletedTask; diff --git a/src/tests/SharedScenarios/BindInteraction/ObservableHandler/MyView.cs b/src/tests/SharedScenarios/BindInteraction/ObservableHandler/MyView.cs index 3ad9d1f..4f7fa3c 100644 --- a/src/tests/SharedScenarios/BindInteraction/ObservableHandler/MyView.cs +++ b/src/tests/SharedScenarios/BindInteraction/ObservableHandler/MyView.cs @@ -7,9 +7,7 @@ namespace SharedScenarios.BindInteraction.ObservableHandler; -/// -/// View that binds an interaction handler. -/// +/// View that binds an interaction handler. #pragma warning disable CS0067 // Event is never used public class MyView : IViewFor, INotifyPropertyChanged { diff --git a/src/tests/SharedScenarios/BindInteraction/ObservableHandler/MyViewModel.cs b/src/tests/SharedScenarios/BindInteraction/ObservableHandler/MyViewModel.cs index c7f72b0..ef0c372 100644 --- a/src/tests/SharedScenarios/BindInteraction/ObservableHandler/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindInteraction/ObservableHandler/MyViewModel.cs @@ -7,22 +7,16 @@ namespace SharedScenarios.BindInteraction.ObservableHandler; -/// -/// ViewModel exposing a string-to-bool interaction. -/// +/// ViewModel exposing a string-to-bool interaction. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private Interaction _confirm = new Interaction(); /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the confirmation interaction. - /// + /// Gets or sets the confirmation interaction. public Interaction Confirm { get => _confirm; diff --git a/src/tests/SharedScenarios/BindInteraction/ObservableHandler/Scenario.cs b/src/tests/SharedScenarios/BindInteraction/ObservableHandler/Scenario.cs index 64f7cf7..847f144 100644 --- a/src/tests/SharedScenarios/BindInteraction/ObservableHandler/Scenario.cs +++ b/src/tests/SharedScenarios/BindInteraction/ObservableHandler/Scenario.cs @@ -7,19 +7,15 @@ namespace SharedScenarios.BindInteraction.ObservableHandler; -/// -/// Exercises BindInteraction with an observable-based handler. -/// +/// Exercises BindInteraction with an observable-based handler. public static class Scenario { - /// - /// Binds an observable handler to the ViewModel's Confirm interaction. - /// + /// Binds an observable handler to the ViewModel's Confirm interaction. /// The source view model. /// The target view. /// A disposable representing the binding. - public static IDisposable Execute(MyViewModel vm, MyView view) - => view.BindInteraction(vm, x => x.Confirm, ctx => + public static IDisposable Execute(MyViewModel vm, MyView view) => + view.BindInteraction(vm, x => x.Confirm, ctx => { ctx.SetOutput(true); return new ReactiveUI.Binding.Observables.ReturnObservable(0); diff --git a/src/tests/SharedScenarios/BindInteraction/TaskHandler/MyView.cs b/src/tests/SharedScenarios/BindInteraction/TaskHandler/MyView.cs index bc6e737..547ed02 100644 --- a/src/tests/SharedScenarios/BindInteraction/TaskHandler/MyView.cs +++ b/src/tests/SharedScenarios/BindInteraction/TaskHandler/MyView.cs @@ -7,9 +7,7 @@ namespace SharedScenarios.BindInteraction.TaskHandler; -/// -/// View that binds an interaction handler. -/// +/// View that binds an interaction handler. #pragma warning disable CS0067 // Event is never used public class MyView : IViewFor, INotifyPropertyChanged { diff --git a/src/tests/SharedScenarios/BindInteraction/TaskHandler/MyViewModel.cs b/src/tests/SharedScenarios/BindInteraction/TaskHandler/MyViewModel.cs index 7094ab0..b088df7 100644 --- a/src/tests/SharedScenarios/BindInteraction/TaskHandler/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindInteraction/TaskHandler/MyViewModel.cs @@ -7,22 +7,16 @@ namespace SharedScenarios.BindInteraction.TaskHandler; -/// -/// ViewModel exposing a string-to-bool interaction. -/// +/// ViewModel exposing a string-to-bool interaction. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private Interaction _confirm = new Interaction(); /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the confirmation interaction. - /// + /// Gets or sets the confirmation interaction. public Interaction Confirm { get => _confirm; diff --git a/src/tests/SharedScenarios/BindInteraction/TaskHandler/Scenario.cs b/src/tests/SharedScenarios/BindInteraction/TaskHandler/Scenario.cs index 3254d79..4d2abeb 100644 --- a/src/tests/SharedScenarios/BindInteraction/TaskHandler/Scenario.cs +++ b/src/tests/SharedScenarios/BindInteraction/TaskHandler/Scenario.cs @@ -8,19 +8,15 @@ namespace SharedScenarios.BindInteraction.TaskHandler; -/// -/// Exercises BindInteraction with a task-based handler. -/// +/// Exercises BindInteraction with a task-based handler. public static class Scenario { - /// - /// Binds a task handler to the ViewModel's Confirm interaction. - /// + /// Binds a task handler to the ViewModel's Confirm interaction. /// The source view model. /// The target view. /// A disposable representing the binding. - public static IDisposable Execute(MyViewModel vm, MyView view) - => view.BindInteraction(vm, x => x.Confirm, ctx => + public static IDisposable Execute(MyViewModel vm, MyView view) => + view.BindInteraction(vm, x => x.Confirm, ctx => { ctx.SetOutput(true); return Task.CompletedTask; diff --git a/src/tests/SharedScenarios/BindOneWay/MultipleBindings/MyView.cs b/src/tests/SharedScenarios/BindOneWay/MultipleBindings/MyView.cs index 085fa75..202a3b6 100644 --- a/src/tests/SharedScenarios/BindOneWay/MultipleBindings/MyView.cs +++ b/src/tests/SharedScenarios/BindOneWay/MultipleBindings/MyView.cs @@ -6,27 +6,19 @@ namespace SharedScenarios.BindOneWay.MultipleBindings; -/// -/// Target View with multiple properties. -/// +/// Target View with multiple properties. public class MyView : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _nameText = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private int _ageDisplay; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name text. - /// + /// Gets or sets the name text. public string NameText { get => _nameText; @@ -42,9 +34,7 @@ public string NameText } } - /// - /// Gets or sets the age display. - /// + /// Gets or sets the age display. public int AgeDisplay { get => _ageDisplay; diff --git a/src/tests/SharedScenarios/BindOneWay/MultipleBindings/MyViewModel.cs b/src/tests/SharedScenarios/BindOneWay/MultipleBindings/MyViewModel.cs index 3746342..04fd36b 100644 --- a/src/tests/SharedScenarios/BindOneWay/MultipleBindings/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindOneWay/MultipleBindings/MyViewModel.cs @@ -6,27 +6,19 @@ namespace SharedScenarios.BindOneWay.MultipleBindings; -/// -/// Source ViewModel with multiple properties. -/// +/// Source ViewModel with multiple properties. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private int _age; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; @@ -42,9 +34,7 @@ public string Name } } - /// - /// Gets or sets the age. - /// + /// Gets or sets the age. public int Age { get => _age; diff --git a/src/tests/SharedScenarios/BindOneWay/MultipleBindings/Scenario.cs b/src/tests/SharedScenarios/BindOneWay/MultipleBindings/Scenario.cs index 0926cb7..cc822c5 100644 --- a/src/tests/SharedScenarios/BindOneWay/MultipleBindings/Scenario.cs +++ b/src/tests/SharedScenarios/BindOneWay/MultipleBindings/Scenario.cs @@ -7,17 +7,13 @@ namespace SharedScenarios.BindOneWay.MultipleBindings; -/// -/// Exercises BindOneWay with multiple bindings on the same source/target pair. -/// +/// Exercises BindOneWay with multiple bindings on the same source/target pair. public static class Scenario { - /// - /// Creates two one-way bindings for Name and Age properties. - /// + /// Creates two one-way bindings for Name and Age properties. /// The source view model. /// The target view. /// A tuple of disposables representing the bindings. - public static (IDisposable NameBinding, IDisposable AgeBinding) Execute(MyViewModel vm, MyView view) - => (vm.BindOneWay(view, x => x.Name, x => x.NameText), vm.BindOneWay(view, x => x.Age, x => x.AgeDisplay)); + public static (IDisposable NameBinding, IDisposable AgeBinding) Execute(MyViewModel vm, MyView view) => + (vm.BindOneWay(view, x => x.Name, x => x.NameText), vm.BindOneWay(view, x => x.Age, x => x.AgeDisplay)); } diff --git a/src/tests/SharedScenarios/BindOneWay/MultipleSameTypeBindings/MyView.cs b/src/tests/SharedScenarios/BindOneWay/MultipleSameTypeBindings/MyView.cs index e966e1c..8390564 100644 --- a/src/tests/SharedScenarios/BindOneWay/MultipleSameTypeBindings/MyView.cs +++ b/src/tests/SharedScenarios/BindOneWay/MultipleSameTypeBindings/MyView.cs @@ -6,27 +6,19 @@ namespace SharedScenarios.BindOneWay.MultipleSameTypeBindings; -/// -/// Target View with two string properties. -/// +/// Target View with two string properties. public class MyView : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _firstNameText = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private string _lastNameText = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the first name text. - /// + /// Gets or sets the first name text. public string FirstNameText { get => _firstNameText; @@ -42,9 +34,7 @@ public string FirstNameText } } - /// - /// Gets or sets the last name text. - /// + /// Gets or sets the last name text. public string LastNameText { get => _lastNameText; diff --git a/src/tests/SharedScenarios/BindOneWay/MultipleSameTypeBindings/MyViewModel.cs b/src/tests/SharedScenarios/BindOneWay/MultipleSameTypeBindings/MyViewModel.cs index 004191a..35555fe 100644 --- a/src/tests/SharedScenarios/BindOneWay/MultipleSameTypeBindings/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindOneWay/MultipleSameTypeBindings/MyViewModel.cs @@ -6,27 +6,19 @@ namespace SharedScenarios.BindOneWay.MultipleSameTypeBindings; -/// -/// Source ViewModel with two string properties. -/// +/// Source ViewModel with two string properties. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _firstName = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private string _lastName = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the first name. - /// + /// Gets or sets the first name. public string FirstName { get => _firstName; @@ -42,9 +34,7 @@ public string FirstName } } - /// - /// Gets or sets the last name. - /// + /// Gets or sets the last name. public string LastName { get => _lastName; diff --git a/src/tests/SharedScenarios/BindOneWay/MultipleSameTypeBindings/Scenario.cs b/src/tests/SharedScenarios/BindOneWay/MultipleSameTypeBindings/Scenario.cs index f549473..206d32c 100644 --- a/src/tests/SharedScenarios/BindOneWay/MultipleSameTypeBindings/Scenario.cs +++ b/src/tests/SharedScenarios/BindOneWay/MultipleSameTypeBindings/Scenario.cs @@ -7,18 +7,14 @@ namespace SharedScenarios.BindOneWay.MultipleSameTypeBindings; -/// -/// Exercises BindOneWay with multiple bindings sharing the same type signature (string to string). -/// +/// Exercises BindOneWay with multiple bindings sharing the same type signature (string to string). public static class Scenario { - /// - /// Creates two one-way bindings with the same type signature to test else-if dispatch. - /// + /// Creates two one-way bindings with the same type signature to test else-if dispatch. /// The source view model. /// The target view. /// A tuple of disposables representing the bindings. - public static (IDisposable FirstBinding, IDisposable LastBinding) Execute(MyViewModel vm, MyView view) - => (vm.BindOneWay(view, x => x.FirstName, x => x.FirstNameText), + public static (IDisposable FirstBinding, IDisposable LastBinding) Execute(MyViewModel vm, MyView view) => + (vm.BindOneWay(view, x => x.FirstName, x => x.FirstNameText), vm.BindOneWay(view, x => x.LastName, x => x.LastNameText)); } diff --git a/src/tests/SharedScenarios/BindOneWay/ReactiveObjectSource/MyView.cs b/src/tests/SharedScenarios/BindOneWay/ReactiveObjectSource/MyView.cs index 936229b..7d17202 100644 --- a/src/tests/SharedScenarios/BindOneWay/ReactiveObjectSource/MyView.cs +++ b/src/tests/SharedScenarios/BindOneWay/ReactiveObjectSource/MyView.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.BindOneWay.ReactiveObjectSource; -/// -/// Target View implementing INPC. -/// +/// Target View implementing INPC. public class MyView : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _nameText = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name text. - /// + /// Gets or sets the name text. public string NameText { get => _nameText; diff --git a/src/tests/SharedScenarios/BindOneWay/ReactiveObjectSource/MyViewModel.cs b/src/tests/SharedScenarios/BindOneWay/ReactiveObjectSource/MyViewModel.cs index 1b35507..13c51af 100644 --- a/src/tests/SharedScenarios/BindOneWay/ReactiveObjectSource/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindOneWay/ReactiveObjectSource/MyViewModel.cs @@ -6,19 +6,13 @@ namespace SharedScenarios.BindOneWay.ReactiveObjectSource; -/// -/// Source ViewModel extending ReactiveObject. -/// +/// Source ViewModel extending ReactiveObject. public class MyViewModel : ReactiveObject { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; diff --git a/src/tests/SharedScenarios/BindOneWay/ReactiveObjectSource/Scenario.cs b/src/tests/SharedScenarios/BindOneWay/ReactiveObjectSource/Scenario.cs index fcc955c..c1eacf2 100644 --- a/src/tests/SharedScenarios/BindOneWay/ReactiveObjectSource/Scenario.cs +++ b/src/tests/SharedScenarios/BindOneWay/ReactiveObjectSource/Scenario.cs @@ -7,17 +7,13 @@ namespace SharedScenarios.BindOneWay.ReactiveObjectSource; -/// -/// Exercises BindOneWay with a ReactiveObject source. -/// +/// Exercises BindOneWay with a ReactiveObject source. public static class Scenario { - /// - /// Creates a one-way binding from ReactiveObject ViewModel.Name to View.NameText. - /// + /// Creates a one-way binding from ReactiveObject ViewModel.Name to View.NameText. /// The source view model. /// The target view. /// A disposable representing the binding. - public static IDisposable Execute(MyViewModel vm, MyView view) - => vm.BindOneWay(view, x => x.Name, x => x.NameText); + public static IDisposable Execute(MyViewModel vm, MyView view) => + vm.BindOneWay(view, x => x.Name, x => x.NameText); } diff --git a/src/tests/SharedScenarios/BindOneWay/SinglePropertyIntToInt/MyView.cs b/src/tests/SharedScenarios/BindOneWay/SinglePropertyIntToInt/MyView.cs index f012e30..755fbfb 100644 --- a/src/tests/SharedScenarios/BindOneWay/SinglePropertyIntToInt/MyView.cs +++ b/src/tests/SharedScenarios/BindOneWay/SinglePropertyIntToInt/MyView.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.BindOneWay.SinglePropertyIntToInt; -/// -/// Target View with an integer property. -/// +/// Target View with an integer property. public class MyView : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private int _displayCount; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the display count. - /// + /// Gets or sets the display count. public int DisplayCount { get => _displayCount; diff --git a/src/tests/SharedScenarios/BindOneWay/SinglePropertyIntToInt/MyViewModel.cs b/src/tests/SharedScenarios/BindOneWay/SinglePropertyIntToInt/MyViewModel.cs index ca6bddc..d17505c 100644 --- a/src/tests/SharedScenarios/BindOneWay/SinglePropertyIntToInt/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindOneWay/SinglePropertyIntToInt/MyViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.BindOneWay.SinglePropertyIntToInt; -/// -/// Source ViewModel with an integer property. -/// +/// Source ViewModel with an integer property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private int _count; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the count. - /// + /// Gets or sets the count. public int Count { get => _count; diff --git a/src/tests/SharedScenarios/BindOneWay/SinglePropertyIntToInt/Scenario.cs b/src/tests/SharedScenarios/BindOneWay/SinglePropertyIntToInt/Scenario.cs index 5d374e0..1eb5d5d 100644 --- a/src/tests/SharedScenarios/BindOneWay/SinglePropertyIntToInt/Scenario.cs +++ b/src/tests/SharedScenarios/BindOneWay/SinglePropertyIntToInt/Scenario.cs @@ -7,17 +7,13 @@ namespace SharedScenarios.BindOneWay.SinglePropertyIntToInt; -/// -/// Exercises BindOneWay with int-to-int property binding. -/// +/// Exercises BindOneWay with int-to-int property binding. public static class Scenario { - /// - /// Creates a one-way binding from ViewModel.Count to View.DisplayCount. - /// + /// Creates a one-way binding from ViewModel.Count to View.DisplayCount. /// The source view model. /// The target view. /// A disposable representing the binding. - public static IDisposable Execute(MyViewModel vm, MyView view) - => vm.BindOneWay(view, x => x.Count, x => x.DisplayCount); + public static IDisposable Execute(MyViewModel vm, MyView view) => + vm.BindOneWay(view, x => x.Count, x => x.DisplayCount); } diff --git a/src/tests/SharedScenarios/BindOneWay/SinglePropertyStringToString/MyView.cs b/src/tests/SharedScenarios/BindOneWay/SinglePropertyStringToString/MyView.cs index f508ffa..d3b5274 100644 --- a/src/tests/SharedScenarios/BindOneWay/SinglePropertyStringToString/MyView.cs +++ b/src/tests/SharedScenarios/BindOneWay/SinglePropertyStringToString/MyView.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.BindOneWay.SinglePropertyStringToString; -/// -/// Target View with a string property. -/// +/// Target View with a string property. public class MyView : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _nameText = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name text. - /// + /// Gets or sets the name text. public string NameText { get => _nameText; diff --git a/src/tests/SharedScenarios/BindOneWay/SinglePropertyStringToString/MyViewModel.cs b/src/tests/SharedScenarios/BindOneWay/SinglePropertyStringToString/MyViewModel.cs index b0392f0..c900d30 100644 --- a/src/tests/SharedScenarios/BindOneWay/SinglePropertyStringToString/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindOneWay/SinglePropertyStringToString/MyViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.BindOneWay.SinglePropertyStringToString; -/// -/// Source ViewModel with a string property. -/// +/// Source ViewModel with a string property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; diff --git a/src/tests/SharedScenarios/BindOneWay/SinglePropertyStringToString/Scenario.cs b/src/tests/SharedScenarios/BindOneWay/SinglePropertyStringToString/Scenario.cs index 5ba1f6f..18784e3 100644 --- a/src/tests/SharedScenarios/BindOneWay/SinglePropertyStringToString/Scenario.cs +++ b/src/tests/SharedScenarios/BindOneWay/SinglePropertyStringToString/Scenario.cs @@ -7,17 +7,13 @@ namespace SharedScenarios.BindOneWay.SinglePropertyStringToString; -/// -/// Exercises BindOneWay with string-to-string property binding. -/// +/// Exercises BindOneWay with string-to-string property binding. public static class Scenario { - /// - /// Creates a one-way binding from ViewModel.Name to View.NameText. - /// + /// Creates a one-way binding from ViewModel.Name to View.NameText. /// The source view model. /// The target view. /// A disposable representing the binding. - public static IDisposable Execute(MyViewModel vm, MyView view) - => vm.BindOneWay(view, x => x.Name, x => x.NameText); + public static IDisposable Execute(MyViewModel vm, MyView view) => + vm.BindOneWay(view, x => x.Name, x => x.NameText); } diff --git a/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithConverter/MyView.cs b/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithConverter/MyView.cs index 8d7a155..ee186cf 100644 --- a/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithConverter/MyView.cs +++ b/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithConverter/MyView.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.BindOneWay.SinglePropertyWithConverter; -/// -/// Target View with a string property. -/// +/// Target View with a string property. public class MyView : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _countText = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the count text. - /// + /// Gets or sets the count text. public string CountText { get => _countText; diff --git a/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithConverter/MyViewModel.cs b/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithConverter/MyViewModel.cs index 8bbaeb2..ce67216 100644 --- a/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithConverter/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithConverter/MyViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.BindOneWay.SinglePropertyWithConverter; -/// -/// Source ViewModel with an integer property. -/// +/// Source ViewModel with an integer property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private int _count; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the count. - /// + /// Gets or sets the count. public int Count { get => _count; diff --git a/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithConverter/Scenario.cs b/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithConverter/Scenario.cs index 37e6298..9a0d4ff 100644 --- a/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithConverter/Scenario.cs +++ b/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithConverter/Scenario.cs @@ -7,17 +7,13 @@ namespace SharedScenarios.BindOneWay.SinglePropertyWithConverter; -/// -/// Exercises BindOneWay with a conversion function from int to string. -/// +/// Exercises BindOneWay with a conversion function from int to string. public static class Scenario { - /// - /// Creates a one-way binding from ViewModel.Count to View.CountText with int-to-string conversion. - /// + /// Creates a one-way binding from ViewModel.Count to View.CountText with int-to-string conversion. /// The source view model. /// The target view. /// A disposable representing the binding. - public static IDisposable Execute(MyViewModel vm, MyView view) - => vm.BindOneWay(view, x => x.Count, x => x.CountText, count => count.ToString()); + public static IDisposable Execute(MyViewModel vm, MyView view) => + vm.BindOneWay(view, x => x.Count, x => x.CountText, count => count.ToString()); } diff --git a/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithConverterAndScheduler/MyView.cs b/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithConverterAndScheduler/MyView.cs index 456bf14..43ef6fb 100644 --- a/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithConverterAndScheduler/MyView.cs +++ b/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithConverterAndScheduler/MyView.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.BindOneWay.SinglePropertyWithConverterAndScheduler; -/// -/// Target View with a string property. -/// +/// Target View with a string property. public class MyView : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _countText = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the count text. - /// + /// Gets or sets the count text. public string CountText { get => _countText; diff --git a/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithConverterAndScheduler/MyViewModel.cs b/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithConverterAndScheduler/MyViewModel.cs index e86f044..a327a1c 100644 --- a/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithConverterAndScheduler/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithConverterAndScheduler/MyViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.BindOneWay.SinglePropertyWithConverterAndScheduler; -/// -/// Source ViewModel with an integer property. -/// +/// Source ViewModel with an integer property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private int _count; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the count. - /// + /// Gets or sets the count. public int Count { get => _count; diff --git a/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithConverterAndScheduler/Scenario.cs b/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithConverterAndScheduler/Scenario.cs index 3e8df8d..db1a63c 100644 --- a/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithConverterAndScheduler/Scenario.cs +++ b/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithConverterAndScheduler/Scenario.cs @@ -8,18 +8,14 @@ namespace SharedScenarios.BindOneWay.SinglePropertyWithConverterAndScheduler; -/// -/// Exercises BindOneWay with both a conversion function and a scheduler. -/// +/// Exercises BindOneWay with both a conversion function and a scheduler. public static class Scenario { - /// - /// Creates a one-way binding from ViewModel.Count to View.CountText with int-to-string conversion and scheduler. - /// + /// Creates a one-way binding from ViewModel.Count to View.CountText with int-to-string conversion and scheduler. /// The source view model. /// The target view. /// The scheduler to observe on. /// A disposable representing the binding. - public static IDisposable Execute(MyViewModel vm, MyView view, IScheduler scheduler) - => vm.BindOneWay(view, x => x.Count, x => x.CountText, count => count.ToString(), scheduler); + public static IDisposable Execute(MyViewModel vm, MyView view, IScheduler scheduler) => + vm.BindOneWay(view, x => x.Count, x => x.CountText, count => count.ToString(), scheduler); } diff --git a/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithScheduler/MyView.cs b/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithScheduler/MyView.cs index 72d7b87..9fe2618 100644 --- a/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithScheduler/MyView.cs +++ b/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithScheduler/MyView.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.BindOneWay.SinglePropertyWithScheduler; -/// -/// Target View with a string property. -/// +/// Target View with a string property. public class MyView : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _nameText = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name text. - /// + /// Gets or sets the name text. public string NameText { get => _nameText; diff --git a/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithScheduler/MyViewModel.cs b/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithScheduler/MyViewModel.cs index aa53336..7b824c6 100644 --- a/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithScheduler/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithScheduler/MyViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.BindOneWay.SinglePropertyWithScheduler; -/// -/// Source ViewModel with a string property. -/// +/// Source ViewModel with a string property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; diff --git a/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithScheduler/Scenario.cs b/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithScheduler/Scenario.cs index 9a77168..ecc5e1d 100644 --- a/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithScheduler/Scenario.cs +++ b/src/tests/SharedScenarios/BindOneWay/SinglePropertyWithScheduler/Scenario.cs @@ -8,18 +8,14 @@ namespace SharedScenarios.BindOneWay.SinglePropertyWithScheduler; -/// -/// Exercises BindOneWay with a scheduler parameter. -/// +/// Exercises BindOneWay with a scheduler parameter. public static class Scenario { - /// - /// Creates a one-way binding from ViewModel.Name to View.NameText with a scheduler. - /// + /// Creates a one-way binding from ViewModel.Name to View.NameText with a scheduler. /// The source view model. /// The target view. /// The scheduler to observe on. /// A disposable representing the binding. - public static IDisposable Execute(MyViewModel vm, MyView view, IScheduler scheduler) - => vm.BindOneWay(view, x => x.Name, x => x.NameText, scheduler); + public static IDisposable Execute(MyViewModel vm, MyView view, IScheduler scheduler) => + vm.BindOneWay(view, x => x.Name, x => x.NameText, scheduler); } diff --git a/src/tests/SharedScenarios/BindTo/DifferingTypes/MyView.cs b/src/tests/SharedScenarios/BindTo/DifferingTypes/MyView.cs index 02bcf71..1938435 100644 --- a/src/tests/SharedScenarios/BindTo/DifferingTypes/MyView.cs +++ b/src/tests/SharedScenarios/BindTo/DifferingTypes/MyView.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.BindTo.DifferingTypes; -/// -/// Target View with a string property bound from an int observable. -/// +/// Target View with a string property bound from an int observable. public class MyView : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _caption = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the caption. - /// + /// Gets or sets the caption. public string Caption { get => _caption; diff --git a/src/tests/SharedScenarios/BindTo/DifferingTypes/Scenario.cs b/src/tests/SharedScenarios/BindTo/DifferingTypes/Scenario.cs index 8cb233a..73cfb6b 100644 --- a/src/tests/SharedScenarios/BindTo/DifferingTypes/Scenario.cs +++ b/src/tests/SharedScenarios/BindTo/DifferingTypes/Scenario.cs @@ -7,17 +7,13 @@ namespace SharedScenarios.BindTo.DifferingTypes; -/// -/// Exercises BindTo applying an int observable to a string property, coerced via the converter registry. -/// +/// Exercises BindTo applying an int observable to a string property, coerced via the converter registry. public static class Scenario { - /// - /// Binds the int observable stream to the view's string caption. - /// + /// Binds the int observable stream to the view's string caption. /// The source observable stream. /// The target view. /// A disposable representing the binding. - public static IDisposable Execute(IObservable source, MyView view) - => source.BindTo(view, x => x.Caption); + public static IDisposable Execute(IObservable source, MyView view) => + source.BindTo(view, x => x.Caption); } diff --git a/src/tests/SharedScenarios/BindTo/SameTypeString/MyView.cs b/src/tests/SharedScenarios/BindTo/SameTypeString/MyView.cs index cc5f424..53e8b28 100644 --- a/src/tests/SharedScenarios/BindTo/SameTypeString/MyView.cs +++ b/src/tests/SharedScenarios/BindTo/SameTypeString/MyView.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.BindTo.SameTypeString; -/// -/// Target View with a string property. -/// +/// Target View with a string property. public class MyView : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _caption = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the caption. - /// + /// Gets or sets the caption. public string Caption { get => _caption; diff --git a/src/tests/SharedScenarios/BindTo/SameTypeString/Scenario.cs b/src/tests/SharedScenarios/BindTo/SameTypeString/Scenario.cs index d0f1abe..b79d2c4 100644 --- a/src/tests/SharedScenarios/BindTo/SameTypeString/Scenario.cs +++ b/src/tests/SharedScenarios/BindTo/SameTypeString/Scenario.cs @@ -7,17 +7,13 @@ namespace SharedScenarios.BindTo.SameTypeString; -/// -/// Exercises BindTo applying a string observable to a same-typed string property (direct assignment). -/// +/// Exercises BindTo applying a string observable to a same-typed string property (direct assignment). public static class Scenario { - /// - /// Binds the observable stream to the view's caption. - /// + /// Binds the observable stream to the view's caption. /// The source observable stream. /// The target view. /// A disposable representing the binding. - public static IDisposable Execute(IObservable source, MyView view) - => source.BindTo(view, x => x.Caption); + public static IDisposable Execute(IObservable source, MyView view) => + source.BindTo(view, x => x.Caption); } diff --git a/src/tests/SharedScenarios/BindTo/WithConversionHint/MyView.cs b/src/tests/SharedScenarios/BindTo/WithConversionHint/MyView.cs index 1055723..77faef3 100644 --- a/src/tests/SharedScenarios/BindTo/WithConversionHint/MyView.cs +++ b/src/tests/SharedScenarios/BindTo/WithConversionHint/MyView.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.BindTo.WithConversionHint; -/// -/// Target View with a string property bound using a conversion hint. -/// +/// Target View with a string property bound using a conversion hint. public class MyView : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _caption = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the caption. - /// + /// Gets or sets the caption. public string Caption { get => _caption; diff --git a/src/tests/SharedScenarios/BindTo/WithConversionHint/Scenario.cs b/src/tests/SharedScenarios/BindTo/WithConversionHint/Scenario.cs index c8f63e8..8f1eee7 100644 --- a/src/tests/SharedScenarios/BindTo/WithConversionHint/Scenario.cs +++ b/src/tests/SharedScenarios/BindTo/WithConversionHint/Scenario.cs @@ -7,17 +7,13 @@ namespace SharedScenarios.BindTo.WithConversionHint; -/// -/// Exercises BindTo with a conversion hint forwarded to the resolved converter. -/// +/// Exercises BindTo with a conversion hint forwarded to the resolved converter. public static class Scenario { - /// - /// Binds the int observable stream to the view's string caption using a conversion hint. - /// + /// Binds the int observable stream to the view's string caption using a conversion hint. /// The source observable stream. /// The target view. /// A disposable representing the binding. - public static IDisposable Execute(IObservable source, MyView view) - => source.BindTo(view, x => x.Caption, (object)"D2"); + public static IDisposable Execute(IObservable source, MyView view) => + source.BindTo(view, x => x.Caption, (object)"D2"); } diff --git a/src/tests/SharedScenarios/BindTo/WithConverterOverride/MyView.cs b/src/tests/SharedScenarios/BindTo/WithConverterOverride/MyView.cs index 6de9f2f..0422788 100644 --- a/src/tests/SharedScenarios/BindTo/WithConverterOverride/MyView.cs +++ b/src/tests/SharedScenarios/BindTo/WithConverterOverride/MyView.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.BindTo.WithConverterOverride; -/// -/// Target View with a string property bound via an explicit converter. -/// +/// Target View with a string property bound via an explicit converter. public class MyView : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _caption = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the caption. - /// + /// Gets or sets the caption. public string Caption { get => _caption; diff --git a/src/tests/SharedScenarios/BindTo/WithConverterOverride/Scenario.cs b/src/tests/SharedScenarios/BindTo/WithConverterOverride/Scenario.cs index 0a7b31f..899e2f7 100644 --- a/src/tests/SharedScenarios/BindTo/WithConverterOverride/Scenario.cs +++ b/src/tests/SharedScenarios/BindTo/WithConverterOverride/Scenario.cs @@ -7,18 +7,14 @@ namespace SharedScenarios.BindTo.WithConverterOverride; -/// -/// Exercises BindTo with an explicit override. -/// +/// Exercises BindTo with an explicit override. public static class Scenario { - /// - /// Binds the int observable stream to the view's string caption using the supplied converter. - /// + /// Binds the int observable stream to the view's string caption using the supplied converter. /// The source observable stream. /// The target view. /// The explicit converter to use. /// A disposable representing the binding. - public static IDisposable Execute(IObservable source, MyView view, IBindingTypeConverter converter) - => source.BindTo(view, x => x.Caption, converter); + public static IDisposable Execute(IObservable source, MyView view, IBindingTypeConverter converter) => + source.BindTo(view, x => x.Caption, converter); } diff --git a/src/tests/SharedScenarios/BindTwoWay/MixedWithBindOneWay/MyView.cs b/src/tests/SharedScenarios/BindTwoWay/MixedWithBindOneWay/MyView.cs index 79f3d4b..054eb48 100644 --- a/src/tests/SharedScenarios/BindTwoWay/MixedWithBindOneWay/MyView.cs +++ b/src/tests/SharedScenarios/BindTwoWay/MixedWithBindOneWay/MyView.cs @@ -6,27 +6,19 @@ namespace SharedScenarios.BindTwoWay.MixedWithBindOneWay; -/// -/// Target View with properties for mixed binding. -/// +/// Target View with properties for mixed binding. public class MyView : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _nameText = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private int _countDisplay; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name text. - /// + /// Gets or sets the name text. public string NameText { get => _nameText; @@ -42,9 +34,7 @@ public string NameText } } - /// - /// Gets or sets the count display. - /// + /// Gets or sets the count display. public int CountDisplay { get => _countDisplay; diff --git a/src/tests/SharedScenarios/BindTwoWay/MixedWithBindOneWay/MyViewModel.cs b/src/tests/SharedScenarios/BindTwoWay/MixedWithBindOneWay/MyViewModel.cs index 55404fc..caeedf6 100644 --- a/src/tests/SharedScenarios/BindTwoWay/MixedWithBindOneWay/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindTwoWay/MixedWithBindOneWay/MyViewModel.cs @@ -6,27 +6,19 @@ namespace SharedScenarios.BindTwoWay.MixedWithBindOneWay; -/// -/// Source ViewModel with properties for mixed binding. -/// +/// Source ViewModel with properties for mixed binding. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private int _readOnlyCount; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; @@ -42,9 +34,7 @@ public string Name } } - /// - /// Gets or sets the read-only count. - /// + /// Gets or sets the read-only count. public int ReadOnlyCount { get => _readOnlyCount; diff --git a/src/tests/SharedScenarios/BindTwoWay/MixedWithBindOneWay/Scenario.cs b/src/tests/SharedScenarios/BindTwoWay/MixedWithBindOneWay/Scenario.cs index f5f08dd..fedbbf3 100644 --- a/src/tests/SharedScenarios/BindTwoWay/MixedWithBindOneWay/Scenario.cs +++ b/src/tests/SharedScenarios/BindTwoWay/MixedWithBindOneWay/Scenario.cs @@ -7,18 +7,14 @@ namespace SharedScenarios.BindTwoWay.MixedWithBindOneWay; -/// -/// Exercises mixed BindTwoWay and BindOneWay in the same compilation. -/// +/// Exercises mixed BindTwoWay and BindOneWay in the same compilation. public static class Scenario { - /// - /// Creates a two-way binding for Name and a one-way binding for ReadOnlyCount. - /// + /// Creates a two-way binding for Name and a one-way binding for ReadOnlyCount. /// The source view model. /// The target view. /// A tuple of disposables representing the bindings. - public static (IDisposable TwoWay, IDisposable OneWay) Execute(MyViewModel vm, MyView view) - => (vm.BindTwoWay(view, x => x.Name, x => x.NameText), + public static (IDisposable TwoWay, IDisposable OneWay) Execute(MyViewModel vm, MyView view) => + (vm.BindTwoWay(view, x => x.Name, x => x.NameText), vm.BindOneWay(view, x => x.ReadOnlyCount, x => x.CountDisplay)); } diff --git a/src/tests/SharedScenarios/BindTwoWay/MultipleBindings/MyView.cs b/src/tests/SharedScenarios/BindTwoWay/MultipleBindings/MyView.cs index 6e21ecb..e6f8693 100644 --- a/src/tests/SharedScenarios/BindTwoWay/MultipleBindings/MyView.cs +++ b/src/tests/SharedScenarios/BindTwoWay/MultipleBindings/MyView.cs @@ -6,27 +6,19 @@ namespace SharedScenarios.BindTwoWay.MultipleBindings; -/// -/// Target View with multiple properties. -/// +/// Target View with multiple properties. public class MyView : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _nameText = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private int _ageDisplay; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name text. - /// + /// Gets or sets the name text. public string NameText { get => _nameText; @@ -42,9 +34,7 @@ public string NameText } } - /// - /// Gets or sets the age display. - /// + /// Gets or sets the age display. public int AgeDisplay { get => _ageDisplay; diff --git a/src/tests/SharedScenarios/BindTwoWay/MultipleBindings/MyViewModel.cs b/src/tests/SharedScenarios/BindTwoWay/MultipleBindings/MyViewModel.cs index 20b96f4..2ab693f 100644 --- a/src/tests/SharedScenarios/BindTwoWay/MultipleBindings/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindTwoWay/MultipleBindings/MyViewModel.cs @@ -6,27 +6,19 @@ namespace SharedScenarios.BindTwoWay.MultipleBindings; -/// -/// Source ViewModel with multiple properties. -/// +/// Source ViewModel with multiple properties. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private int _age; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; @@ -42,9 +34,7 @@ public string Name } } - /// - /// Gets or sets the age. - /// + /// Gets or sets the age. public int Age { get => _age; diff --git a/src/tests/SharedScenarios/BindTwoWay/MultipleBindings/Scenario.cs b/src/tests/SharedScenarios/BindTwoWay/MultipleBindings/Scenario.cs index ffa53b2..e6618fc 100644 --- a/src/tests/SharedScenarios/BindTwoWay/MultipleBindings/Scenario.cs +++ b/src/tests/SharedScenarios/BindTwoWay/MultipleBindings/Scenario.cs @@ -7,17 +7,13 @@ namespace SharedScenarios.BindTwoWay.MultipleBindings; -/// -/// Exercises BindTwoWay with multiple bindings on the same source/target pair. -/// +/// Exercises BindTwoWay with multiple bindings on the same source/target pair. public static class Scenario { - /// - /// Creates two two-way bindings for Name and Age properties. - /// + /// Creates two-way bindings for Name and Age properties. /// The source view model. /// The target view. /// A tuple of disposables representing the bindings. - public static (IDisposable NameBinding, IDisposable AgeBinding) Execute(MyViewModel vm, MyView view) - => (vm.BindTwoWay(view, x => x.Name, x => x.NameText), vm.BindTwoWay(view, x => x.Age, x => x.AgeDisplay)); + public static (IDisposable NameBinding, IDisposable AgeBinding) Execute(MyViewModel vm, MyView view) => + (vm.BindTwoWay(view, x => x.Name, x => x.NameText), vm.BindTwoWay(view, x => x.Age, x => x.AgeDisplay)); } diff --git a/src/tests/SharedScenarios/BindTwoWay/MultipleSameTypeBindings/MyView.cs b/src/tests/SharedScenarios/BindTwoWay/MultipleSameTypeBindings/MyView.cs index 10331f5..1d948b8 100644 --- a/src/tests/SharedScenarios/BindTwoWay/MultipleSameTypeBindings/MyView.cs +++ b/src/tests/SharedScenarios/BindTwoWay/MultipleSameTypeBindings/MyView.cs @@ -6,27 +6,19 @@ namespace SharedScenarios.BindTwoWay.MultipleSameTypeBindings; -/// -/// Target View with two string properties. -/// +/// Target View with two string properties. public class MyView : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _firstNameText = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private string _lastNameText = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the first name text. - /// + /// Gets or sets the first name text. public string FirstNameText { get => _firstNameText; @@ -42,9 +34,7 @@ public string FirstNameText } } - /// - /// Gets or sets the last name text. - /// + /// Gets or sets the last name text. public string LastNameText { get => _lastNameText; diff --git a/src/tests/SharedScenarios/BindTwoWay/MultipleSameTypeBindings/MyViewModel.cs b/src/tests/SharedScenarios/BindTwoWay/MultipleSameTypeBindings/MyViewModel.cs index d068419..e460ac8 100644 --- a/src/tests/SharedScenarios/BindTwoWay/MultipleSameTypeBindings/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindTwoWay/MultipleSameTypeBindings/MyViewModel.cs @@ -6,27 +6,19 @@ namespace SharedScenarios.BindTwoWay.MultipleSameTypeBindings; -/// -/// Source ViewModel with two string properties. -/// +/// Source ViewModel with two string properties. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _firstName = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private string _lastName = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the first name. - /// + /// Gets or sets the first name. public string FirstName { get => _firstName; @@ -42,9 +34,7 @@ public string FirstName } } - /// - /// Gets or sets the last name. - /// + /// Gets or sets the last name. public string LastName { get => _lastName; diff --git a/src/tests/SharedScenarios/BindTwoWay/MultipleSameTypeBindings/Scenario.cs b/src/tests/SharedScenarios/BindTwoWay/MultipleSameTypeBindings/Scenario.cs index 7d00340..ebf8f78 100644 --- a/src/tests/SharedScenarios/BindTwoWay/MultipleSameTypeBindings/Scenario.cs +++ b/src/tests/SharedScenarios/BindTwoWay/MultipleSameTypeBindings/Scenario.cs @@ -7,18 +7,14 @@ namespace SharedScenarios.BindTwoWay.MultipleSameTypeBindings; -/// -/// Exercises BindTwoWay with multiple bindings sharing the same type signature (string to string). -/// +/// Exercises BindTwoWay with multiple bindings sharing the same type signature (string to string). public static class Scenario { - /// - /// Creates two two-way bindings with the same type signature to test else-if dispatch. - /// + /// Creates two-way bindings with the same type signature to test else-if dispatch. /// The source view model. /// The target view. /// A tuple of disposables representing the bindings. - public static (IDisposable FirstBinding, IDisposable LastBinding) Execute(MyViewModel vm, MyView view) - => (vm.BindTwoWay(view, x => x.FirstName, x => x.FirstNameText), + public static (IDisposable FirstBinding, IDisposable LastBinding) Execute(MyViewModel vm, MyView view) => + (vm.BindTwoWay(view, x => x.FirstName, x => x.FirstNameText), vm.BindTwoWay(view, x => x.LastName, x => x.LastNameText)); } diff --git a/src/tests/SharedScenarios/BindTwoWay/ReactiveObjectBoth/MyView.cs b/src/tests/SharedScenarios/BindTwoWay/ReactiveObjectBoth/MyView.cs index 1d45d47..55cd0c2 100644 --- a/src/tests/SharedScenarios/BindTwoWay/ReactiveObjectBoth/MyView.cs +++ b/src/tests/SharedScenarios/BindTwoWay/ReactiveObjectBoth/MyView.cs @@ -6,19 +6,13 @@ namespace SharedScenarios.BindTwoWay.ReactiveObjectBoth; -/// -/// Target View extending ReactiveObject. -/// +/// Target View extending ReactiveObject. public class MyView : ReactiveObject { - /// - /// The backing field for . - /// + /// The backing field for . private string _nameText = string.Empty; - /// - /// Gets or sets the name text. - /// + /// Gets or sets the name text. public string NameText { get => _nameText; diff --git a/src/tests/SharedScenarios/BindTwoWay/ReactiveObjectBoth/MyViewModel.cs b/src/tests/SharedScenarios/BindTwoWay/ReactiveObjectBoth/MyViewModel.cs index f92cd96..e5f273d 100644 --- a/src/tests/SharedScenarios/BindTwoWay/ReactiveObjectBoth/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindTwoWay/ReactiveObjectBoth/MyViewModel.cs @@ -6,19 +6,13 @@ namespace SharedScenarios.BindTwoWay.ReactiveObjectBoth; -/// -/// Source ViewModel extending ReactiveObject. -/// +/// Source ViewModel extending ReactiveObject. public class MyViewModel : ReactiveObject { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; diff --git a/src/tests/SharedScenarios/BindTwoWay/ReactiveObjectBoth/Scenario.cs b/src/tests/SharedScenarios/BindTwoWay/ReactiveObjectBoth/Scenario.cs index a8e6cd6..0d48525 100644 --- a/src/tests/SharedScenarios/BindTwoWay/ReactiveObjectBoth/Scenario.cs +++ b/src/tests/SharedScenarios/BindTwoWay/ReactiveObjectBoth/Scenario.cs @@ -7,17 +7,13 @@ namespace SharedScenarios.BindTwoWay.ReactiveObjectBoth; -/// -/// Exercises BindTwoWay with both source and target as ReactiveObject. -/// +/// Exercises BindTwoWay with both source and target as ReactiveObject. public static class Scenario { - /// - /// Creates a two-way binding between ReactiveObject ViewModel.Name and ReactiveObject View.NameText. - /// + /// Creates a two-way binding between ReactiveObject ViewModel.Name and ReactiveObject View.NameText. /// The source view model. /// The target view. /// A disposable representing the binding. - public static IDisposable Execute(MyViewModel vm, MyView view) - => vm.BindTwoWay(view, x => x.Name, x => x.NameText); + public static IDisposable Execute(MyViewModel vm, MyView view) => + vm.BindTwoWay(view, x => x.Name, x => x.NameText); } diff --git a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyIntToInt/MyView.cs b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyIntToInt/MyView.cs index 2fba54c..20c6639 100644 --- a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyIntToInt/MyView.cs +++ b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyIntToInt/MyView.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.BindTwoWay.SinglePropertyIntToInt; -/// -/// Target View with an integer property. -/// +/// Target View with an integer property. public class MyView : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private int _displayCount; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the display count. - /// + /// Gets or sets the display count. public int DisplayCount { get => _displayCount; diff --git a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyIntToInt/MyViewModel.cs b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyIntToInt/MyViewModel.cs index 586ffe9..3c94878 100644 --- a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyIntToInt/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyIntToInt/MyViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.BindTwoWay.SinglePropertyIntToInt; -/// -/// Source ViewModel with an integer property. -/// +/// Source ViewModel with an integer property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private int _count; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the count. - /// + /// Gets or sets the count. public int Count { get => _count; diff --git a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyIntToInt/Scenario.cs b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyIntToInt/Scenario.cs index 5d36931..9e4c4f7 100644 --- a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyIntToInt/Scenario.cs +++ b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyIntToInt/Scenario.cs @@ -7,17 +7,13 @@ namespace SharedScenarios.BindTwoWay.SinglePropertyIntToInt; -/// -/// Exercises BindTwoWay with int-to-int property binding. -/// +/// Exercises BindTwoWay with int-to-int property binding. public static class Scenario { - /// - /// Creates a two-way binding between ViewModel.Count and View.DisplayCount. - /// + /// Creates a two-way binding between ViewModel.Count and View.DisplayCount. /// The source view model. /// The target view. /// A disposable representing the binding. - public static IDisposable Execute(MyViewModel vm, MyView view) - => vm.BindTwoWay(view, x => x.Count, x => x.DisplayCount); + public static IDisposable Execute(MyViewModel vm, MyView view) => + vm.BindTwoWay(view, x => x.Count, x => x.DisplayCount); } diff --git a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyStringToString/MyView.cs b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyStringToString/MyView.cs index 4f0479b..49dd216 100644 --- a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyStringToString/MyView.cs +++ b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyStringToString/MyView.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.BindTwoWay.SinglePropertyStringToString; -/// -/// Target View with a string property. -/// +/// Target View with a string property. public class MyView : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _nameText = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name text. - /// + /// Gets or sets the name text. public string NameText { get => _nameText; diff --git a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyStringToString/MyViewModel.cs b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyStringToString/MyViewModel.cs index 06404d8..249df1b 100644 --- a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyStringToString/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyStringToString/MyViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.BindTwoWay.SinglePropertyStringToString; -/// -/// Source ViewModel with a string property. -/// +/// Source ViewModel with a string property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; diff --git a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyStringToString/Scenario.cs b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyStringToString/Scenario.cs index 3e18eb4..2ba8bcb 100644 --- a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyStringToString/Scenario.cs +++ b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyStringToString/Scenario.cs @@ -7,17 +7,13 @@ namespace SharedScenarios.BindTwoWay.SinglePropertyStringToString; -/// -/// Exercises BindTwoWay with string-to-string property binding. -/// +/// Exercises BindTwoWay with string-to-string property binding. public static class Scenario { - /// - /// Creates a two-way binding between ViewModel.Name and View.NameText. - /// + /// Creates a two-way binding between ViewModel.Name and View.NameText. /// The source view model. /// The target view. /// A disposable representing the binding. - public static IDisposable Execute(MyViewModel vm, MyView view) - => vm.BindTwoWay(view, x => x.Name, x => x.NameText); + public static IDisposable Execute(MyViewModel vm, MyView view) => + vm.BindTwoWay(view, x => x.Name, x => x.NameText); } diff --git a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithConverters/MyView.cs b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithConverters/MyView.cs index 3ca3fb4..0d0206a 100644 --- a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithConverters/MyView.cs +++ b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithConverters/MyView.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.BindTwoWay.SinglePropertyWithConverters; -/// -/// Target View with a string property. -/// +/// Target View with a string property. public class MyView : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _countText = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the count text. - /// + /// Gets or sets the count text. public string CountText { get => _countText; diff --git a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithConverters/MyViewModel.cs b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithConverters/MyViewModel.cs index 376ef9c..ab20636 100644 --- a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithConverters/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithConverters/MyViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.BindTwoWay.SinglePropertyWithConverters; -/// -/// Source ViewModel with an integer property. -/// +/// Source ViewModel with an integer property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private int _count; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the count. - /// + /// Gets or sets the count. public int Count { get => _count; diff --git a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithConverters/Scenario.cs b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithConverters/Scenario.cs index 0b5583a..77bcc5b 100644 --- a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithConverters/Scenario.cs +++ b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithConverters/Scenario.cs @@ -7,19 +7,15 @@ namespace SharedScenarios.BindTwoWay.SinglePropertyWithConverters; -/// -/// Exercises BindTwoWay with conversion functions between int and string. -/// +/// Exercises BindTwoWay with conversion functions between int and string. public static class Scenario { - /// - /// Creates a two-way binding between ViewModel.Count and View.CountText with int-string converters. - /// + /// Creates a two-way binding between ViewModel.Count and View.CountText with int-string converters. /// The source view model. /// The target view. /// A disposable representing the binding. - public static IDisposable Execute(MyViewModel vm, MyView view) - => vm.BindTwoWay( + public static IDisposable Execute(MyViewModel vm, MyView view) => + vm.BindTwoWay( view, x => x.Count, x => x.CountText, diff --git a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithConvertersAndScheduler/MyView.cs b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithConvertersAndScheduler/MyView.cs index 7f933fb..c62d5da 100644 --- a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithConvertersAndScheduler/MyView.cs +++ b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithConvertersAndScheduler/MyView.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.BindTwoWay.SinglePropertyWithConvertersAndScheduler; -/// -/// Target View with a string property. -/// +/// Target View with a string property. public class MyView : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _countText = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the count text. - /// + /// Gets or sets the count text. public string CountText { get => _countText; diff --git a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithConvertersAndScheduler/MyViewModel.cs b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithConvertersAndScheduler/MyViewModel.cs index 371d01b..35ef9bc 100644 --- a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithConvertersAndScheduler/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithConvertersAndScheduler/MyViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.BindTwoWay.SinglePropertyWithConvertersAndScheduler; -/// -/// Source ViewModel with an integer property. -/// +/// Source ViewModel with an integer property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private int _count; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the count. - /// + /// Gets or sets the count. public int Count { get => _count; diff --git a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithConvertersAndScheduler/Scenario.cs b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithConvertersAndScheduler/Scenario.cs index 7c6d227..728302f 100644 --- a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithConvertersAndScheduler/Scenario.cs +++ b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithConvertersAndScheduler/Scenario.cs @@ -8,20 +8,16 @@ namespace SharedScenarios.BindTwoWay.SinglePropertyWithConvertersAndScheduler; -/// -/// Exercises BindTwoWay with conversion functions and a scheduler. -/// +/// Exercises BindTwoWay with conversion functions and a scheduler. public static class Scenario { - /// - /// Creates a two-way binding between ViewModel.Count and View.CountText with converters and scheduler. - /// + /// Creates a two-way binding between ViewModel.Count and View.CountText with converters and scheduler. /// The source view model. /// The target view. /// The scheduler to observe on. /// A disposable representing the binding. - public static IDisposable Execute(MyViewModel vm, MyView view, IScheduler scheduler) - => vm.BindTwoWay( + public static IDisposable Execute(MyViewModel vm, MyView view, IScheduler scheduler) => + vm.BindTwoWay( view, x => x.Count, x => x.CountText, diff --git a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithScheduler/MyView.cs b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithScheduler/MyView.cs index 6b6ed30..4d3430b 100644 --- a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithScheduler/MyView.cs +++ b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithScheduler/MyView.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.BindTwoWay.SinglePropertyWithScheduler; -/// -/// Target View with a string property. -/// +/// Target View with a string property. public class MyView : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _nameText = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name text. - /// + /// Gets or sets the name text. public string NameText { get => _nameText; diff --git a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithScheduler/MyViewModel.cs b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithScheduler/MyViewModel.cs index baedd0f..1a8b3bb 100644 --- a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithScheduler/MyViewModel.cs +++ b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithScheduler/MyViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.BindTwoWay.SinglePropertyWithScheduler; -/// -/// Source ViewModel with a string property. -/// +/// Source ViewModel with a string property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; diff --git a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithScheduler/Scenario.cs b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithScheduler/Scenario.cs index d048be5..953fba2 100644 --- a/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithScheduler/Scenario.cs +++ b/src/tests/SharedScenarios/BindTwoWay/SinglePropertyWithScheduler/Scenario.cs @@ -8,18 +8,14 @@ namespace SharedScenarios.BindTwoWay.SinglePropertyWithScheduler; -/// -/// Exercises BindTwoWay with a scheduler parameter. -/// +/// Exercises BindTwoWay with a scheduler parameter. public static class Scenario { - /// - /// Creates a two-way binding between ViewModel.Name and View.NameText with a scheduler. - /// + /// Creates a two-way binding between ViewModel.Name and View.NameText with a scheduler. /// The source view model. /// The target view. /// The scheduler to observe on. /// A disposable representing the binding. - public static IDisposable Execute(MyViewModel vm, MyView view, IScheduler scheduler) - => vm.BindTwoWay(view, x => x.Name, x => x.NameText, scheduler); + public static IDisposable Execute(MyViewModel vm, MyView view, IScheduler scheduler) => + vm.BindTwoWay(view, x => x.Name, x => x.NameText, scheduler); } diff --git a/src/tests/SharedScenarios/OneWayBind/MultipleBindings/MyView.cs b/src/tests/SharedScenarios/OneWayBind/MultipleBindings/MyView.cs index 3555c90..056f46c 100644 --- a/src/tests/SharedScenarios/OneWayBind/MultipleBindings/MyView.cs +++ b/src/tests/SharedScenarios/OneWayBind/MultipleBindings/MyView.cs @@ -7,19 +7,13 @@ namespace SharedScenarios.OneWayBind.MultipleBindings; -/// -/// Target View with multiple properties. -/// +/// Target View with multiple properties. public class MyView : IViewFor, INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _nameText = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private int _ageText; /// @@ -28,9 +22,7 @@ public class MyView : IViewFor, INotifyPropertyChanged /// public object? ViewModel { get; set; } - /// - /// Gets or sets the name text. - /// + /// Gets or sets the name text. public string NameText { get => _nameText; @@ -46,9 +38,7 @@ public string NameText } } - /// - /// Gets or sets the age text. - /// + /// Gets or sets the age text. public int AgeText { get => _ageText; diff --git a/src/tests/SharedScenarios/OneWayBind/MultipleBindings/MyViewModel.cs b/src/tests/SharedScenarios/OneWayBind/MultipleBindings/MyViewModel.cs index 796fa24..aa58400 100644 --- a/src/tests/SharedScenarios/OneWayBind/MultipleBindings/MyViewModel.cs +++ b/src/tests/SharedScenarios/OneWayBind/MultipleBindings/MyViewModel.cs @@ -6,27 +6,19 @@ namespace SharedScenarios.OneWayBind.MultipleBindings; -/// -/// Source ViewModel with multiple properties. -/// +/// Source ViewModel with multiple properties. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private int _age; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; @@ -42,9 +34,7 @@ public string Name } } - /// - /// Gets or sets the age. - /// + /// Gets or sets the age. public int Age { get => _age; diff --git a/src/tests/SharedScenarios/OneWayBind/MultipleBindings/Scenario.cs b/src/tests/SharedScenarios/OneWayBind/MultipleBindings/Scenario.cs index 789e3d4..bf0af1e 100644 --- a/src/tests/SharedScenarios/OneWayBind/MultipleBindings/Scenario.cs +++ b/src/tests/SharedScenarios/OneWayBind/MultipleBindings/Scenario.cs @@ -6,20 +6,16 @@ namespace SharedScenarios.OneWayBind.MultipleBindings; -/// -/// Exercises OneWayBind (view-first) with multiple bindings on the same view/vm pair. -/// +/// Exercises OneWayBind (view-first) with multiple bindings on the same view/vm pair. public static class Scenario { - /// - /// Creates multiple one-way bindings using view-first syntax. - /// + /// Creates multiple one-way bindings using view-first syntax. /// The target view. /// The source view model. /// A tuple of bindings. - public static (IReactiveBinding name, IReactiveBinding age) Execute( + public static (IReactiveBinding name, IReactiveBinding age) Execute( MyView view, - MyViewModel vm) - => (view.OneWayBind(vm, x => x.Name, x => x.NameText), + MyViewModel vm) => + (view.OneWayBind(vm, x => x.Name, x => x.NameText), view.OneWayBind(vm, x => x.Age, x => x.AgeText)); } diff --git a/src/tests/SharedScenarios/OneWayBind/SinglePropertyIntToInt/MyView.cs b/src/tests/SharedScenarios/OneWayBind/SinglePropertyIntToInt/MyView.cs index 0555000..fb7cee5 100644 --- a/src/tests/SharedScenarios/OneWayBind/SinglePropertyIntToInt/MyView.cs +++ b/src/tests/SharedScenarios/OneWayBind/SinglePropertyIntToInt/MyView.cs @@ -7,14 +7,10 @@ namespace SharedScenarios.OneWayBind.SinglePropertyIntToInt; -/// -/// Target View implementing IViewFor with an integer property. -/// +/// Target View implementing IViewFor with an integer property. public class MyView : IViewFor, INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private int _countValue; /// @@ -23,9 +19,7 @@ public class MyView : IViewFor, INotifyPropertyChanged /// public object? ViewModel { get; set; } - /// - /// Gets or sets the count value. - /// + /// Gets or sets the count value. public int CountValue { get => _countValue; diff --git a/src/tests/SharedScenarios/OneWayBind/SinglePropertyIntToInt/MyViewModel.cs b/src/tests/SharedScenarios/OneWayBind/SinglePropertyIntToInt/MyViewModel.cs index 1cb1f26..e0fbaa1 100644 --- a/src/tests/SharedScenarios/OneWayBind/SinglePropertyIntToInt/MyViewModel.cs +++ b/src/tests/SharedScenarios/OneWayBind/SinglePropertyIntToInt/MyViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.OneWayBind.SinglePropertyIntToInt; -/// -/// Source ViewModel with an integer property. -/// +/// Source ViewModel with an integer property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private int _count; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the count. - /// + /// Gets or sets the count. public int Count { get => _count; diff --git a/src/tests/SharedScenarios/OneWayBind/SinglePropertyIntToInt/Scenario.cs b/src/tests/SharedScenarios/OneWayBind/SinglePropertyIntToInt/Scenario.cs index 2f88d78..5682d77 100644 --- a/src/tests/SharedScenarios/OneWayBind/SinglePropertyIntToInt/Scenario.cs +++ b/src/tests/SharedScenarios/OneWayBind/SinglePropertyIntToInt/Scenario.cs @@ -6,17 +6,13 @@ namespace SharedScenarios.OneWayBind.SinglePropertyIntToInt; -/// -/// Exercises OneWayBind (view-first) with int-to-int property binding. -/// +/// Exercises OneWayBind (view-first) with int-to-int property binding. public static class Scenario { - /// - /// Creates a one-way binding from ViewModel.Count to View.CountValue. - /// + /// Creates a one-way binding from ViewModel.Count to View.CountValue. /// The target view. /// The source view model. /// A reactive binding representing the binding. - public static IReactiveBinding Execute(MyView view, MyViewModel vm) - => view.OneWayBind(vm, x => x.Count, x => x.CountValue); + public static IReactiveBinding Execute(MyView view, MyViewModel vm) => + view.OneWayBind(vm, x => x.Count, x => x.CountValue); } diff --git a/src/tests/SharedScenarios/OneWayBind/SinglePropertyStringToString/MyView.cs b/src/tests/SharedScenarios/OneWayBind/SinglePropertyStringToString/MyView.cs index ff7651c..ac4bf97 100644 --- a/src/tests/SharedScenarios/OneWayBind/SinglePropertyStringToString/MyView.cs +++ b/src/tests/SharedScenarios/OneWayBind/SinglePropertyStringToString/MyView.cs @@ -7,14 +7,10 @@ namespace SharedScenarios.OneWayBind.SinglePropertyStringToString; -/// -/// Target View implementing IViewFor with a string property. -/// +/// Target View implementing IViewFor with a string property. public class MyView : IViewFor, INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _nameText = string.Empty; /// @@ -23,9 +19,7 @@ public class MyView : IViewFor, INotifyPropertyChanged /// public object? ViewModel { get; set; } - /// - /// Gets or sets the name text. - /// + /// Gets or sets the name text. public string NameText { get => _nameText; diff --git a/src/tests/SharedScenarios/OneWayBind/SinglePropertyStringToString/MyViewModel.cs b/src/tests/SharedScenarios/OneWayBind/SinglePropertyStringToString/MyViewModel.cs index 6b1c854..27f112a 100644 --- a/src/tests/SharedScenarios/OneWayBind/SinglePropertyStringToString/MyViewModel.cs +++ b/src/tests/SharedScenarios/OneWayBind/SinglePropertyStringToString/MyViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.OneWayBind.SinglePropertyStringToString; -/// -/// Source ViewModel with a string property. -/// +/// Source ViewModel with a string property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; diff --git a/src/tests/SharedScenarios/OneWayBind/SinglePropertyStringToString/Scenario.cs b/src/tests/SharedScenarios/OneWayBind/SinglePropertyStringToString/Scenario.cs index dbf51ed..4061613 100644 --- a/src/tests/SharedScenarios/OneWayBind/SinglePropertyStringToString/Scenario.cs +++ b/src/tests/SharedScenarios/OneWayBind/SinglePropertyStringToString/Scenario.cs @@ -6,17 +6,13 @@ namespace SharedScenarios.OneWayBind.SinglePropertyStringToString; -/// -/// Exercises OneWayBind (view-first) with string-to-string property binding. -/// +/// Exercises OneWayBind (view-first) with string-to-string property binding. public static class Scenario { - /// - /// Creates a one-way binding from ViewModel.Name to View.NameText using view-first syntax. - /// + /// Creates a one-way binding from ViewModel.Name to View.NameText using view-first syntax. /// The target view. /// The source view model. /// A reactive binding representing the binding. - public static IReactiveBinding Execute(MyView view, MyViewModel vm) - => view.OneWayBind(vm, x => x.Name, x => x.NameText); + public static IReactiveBinding Execute(MyView view, MyViewModel vm) => + view.OneWayBind(vm, x => x.Name, x => x.NameText); } diff --git a/src/tests/SharedScenarios/OneWayBind/SinglePropertyWithSelector/MyView.cs b/src/tests/SharedScenarios/OneWayBind/SinglePropertyWithSelector/MyView.cs index 39bb2ec..50ff7a9 100644 --- a/src/tests/SharedScenarios/OneWayBind/SinglePropertyWithSelector/MyView.cs +++ b/src/tests/SharedScenarios/OneWayBind/SinglePropertyWithSelector/MyView.cs @@ -7,14 +7,10 @@ namespace SharedScenarios.OneWayBind.SinglePropertyWithSelector; -/// -/// Target View with a string property. -/// +/// Target View with a string property. public class MyView : IViewFor, INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _countText = string.Empty; /// @@ -23,9 +19,7 @@ public class MyView : IViewFor, INotifyPropertyChanged /// public object? ViewModel { get; set; } - /// - /// Gets or sets the count text. - /// + /// Gets or sets the count text. public string CountText { get => _countText; diff --git a/src/tests/SharedScenarios/OneWayBind/SinglePropertyWithSelector/MyViewModel.cs b/src/tests/SharedScenarios/OneWayBind/SinglePropertyWithSelector/MyViewModel.cs index 835f9b7..e4d486d 100644 --- a/src/tests/SharedScenarios/OneWayBind/SinglePropertyWithSelector/MyViewModel.cs +++ b/src/tests/SharedScenarios/OneWayBind/SinglePropertyWithSelector/MyViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.OneWayBind.SinglePropertyWithSelector; -/// -/// Source ViewModel with an integer property. -/// +/// Source ViewModel with an integer property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private int _count; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the count. - /// + /// Gets or sets the count. public int Count { get => _count; diff --git a/src/tests/SharedScenarios/OneWayBind/SinglePropertyWithSelector/Scenario.cs b/src/tests/SharedScenarios/OneWayBind/SinglePropertyWithSelector/Scenario.cs index 9bdf373..bbcd1ed 100644 --- a/src/tests/SharedScenarios/OneWayBind/SinglePropertyWithSelector/Scenario.cs +++ b/src/tests/SharedScenarios/OneWayBind/SinglePropertyWithSelector/Scenario.cs @@ -6,17 +6,13 @@ namespace SharedScenarios.OneWayBind.SinglePropertyWithSelector; -/// -/// Exercises OneWayBind (view-first) with a conversion function from int to string. -/// +/// Exercises OneWayBind (view-first) with a conversion function from int to string. public static class Scenario { - /// - /// Creates a one-way binding from ViewModel.Count to View.CountText with int-to-string conversion. - /// + /// Creates a one-way binding from ViewModel.Count to View.CountText with int-to-string conversion. /// The target view. /// The source view model. /// A reactive binding representing the binding. - public static IReactiveBinding Execute(MyView view, MyViewModel vm) - => view.OneWayBind(vm, x => x.Count, x => x.CountText, count => count.ToString()); + public static IReactiveBinding Execute(MyView view, MyViewModel vm) => + view.OneWayBind(vm, x => x.Count, x => x.CountText, count => count.ToString()); } diff --git a/src/tests/SharedScenarios/OneWayBind/SinglePropertyWithSelectorAndScheduler/MyView.cs b/src/tests/SharedScenarios/OneWayBind/SinglePropertyWithSelectorAndScheduler/MyView.cs index ce86db7..4cff953 100644 --- a/src/tests/SharedScenarios/OneWayBind/SinglePropertyWithSelectorAndScheduler/MyView.cs +++ b/src/tests/SharedScenarios/OneWayBind/SinglePropertyWithSelectorAndScheduler/MyView.cs @@ -7,14 +7,10 @@ namespace SharedScenarios.OneWayBind.SinglePropertyWithSelectorAndScheduler; -/// -/// Target View with a string property. -/// +/// Target View with a string property. public class MyView : IViewFor, INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _countText = string.Empty; /// @@ -23,9 +19,7 @@ public class MyView : IViewFor, INotifyPropertyChanged /// public object? ViewModel { get; set; } - /// - /// Gets or sets the count text. - /// + /// Gets or sets the count text. public string CountText { get => _countText; diff --git a/src/tests/SharedScenarios/OneWayBind/SinglePropertyWithSelectorAndScheduler/MyViewModel.cs b/src/tests/SharedScenarios/OneWayBind/SinglePropertyWithSelectorAndScheduler/MyViewModel.cs index 68b12d5..1768802 100644 --- a/src/tests/SharedScenarios/OneWayBind/SinglePropertyWithSelectorAndScheduler/MyViewModel.cs +++ b/src/tests/SharedScenarios/OneWayBind/SinglePropertyWithSelectorAndScheduler/MyViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.OneWayBind.SinglePropertyWithSelectorAndScheduler; -/// -/// Source ViewModel with an integer property. -/// +/// Source ViewModel with an integer property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private int _count; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the count. - /// + /// Gets or sets the count. public int Count { get => _count; diff --git a/src/tests/SharedScenarios/OneWayBind/SinglePropertyWithSelectorAndScheduler/Scenario.cs b/src/tests/SharedScenarios/OneWayBind/SinglePropertyWithSelectorAndScheduler/Scenario.cs index 764c5b7..d59bc45 100644 --- a/src/tests/SharedScenarios/OneWayBind/SinglePropertyWithSelectorAndScheduler/Scenario.cs +++ b/src/tests/SharedScenarios/OneWayBind/SinglePropertyWithSelectorAndScheduler/Scenario.cs @@ -7,18 +7,14 @@ namespace SharedScenarios.OneWayBind.SinglePropertyWithSelectorAndScheduler; -/// -/// Exercises OneWayBind (view-first) with a conversion function and scheduler. -/// +/// Exercises OneWayBind (view-first) with a conversion function and scheduler. public static class Scenario { - /// - /// Creates a one-way binding from ViewModel.Count to View.CountText with int-to-string conversion and scheduler. - /// + /// Creates a one-way binding from ViewModel.Count to View.CountText with int-to-string conversion and scheduler. /// The target view. /// The source view model. /// The scheduler to observe on. /// A reactive binding representing the binding. - public static IReactiveBinding Execute(MyView view, MyViewModel vm, IScheduler scheduler) - => view.OneWayBind(vm, x => x.Count, x => x.CountText, count => count.ToString(), scheduler); + public static IReactiveBinding Execute(MyView view, MyViewModel vm, IScheduler scheduler) => + view.OneWayBind(vm, x => x.Count, x => x.CountText, count => count.ToString(), scheduler); } diff --git a/src/tests/SharedScenarios/OneWayBind/TwoSameTypeBindings/MyView.cs b/src/tests/SharedScenarios/OneWayBind/TwoSameTypeBindings/MyView.cs index f6bdd44..87bbc5c 100644 --- a/src/tests/SharedScenarios/OneWayBind/TwoSameTypeBindings/MyView.cs +++ b/src/tests/SharedScenarios/OneWayBind/TwoSameTypeBindings/MyView.cs @@ -7,19 +7,13 @@ namespace SharedScenarios.OneWayBind.TwoSameTypeBindings; -/// -/// Target View with two string properties to test same-type-signature grouping. -/// +/// Target View with two string properties to test same-type-signature grouping. public class MyView : IViewFor, INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _firstNameText = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private string _lastNameText = string.Empty; /// @@ -28,9 +22,7 @@ public class MyView : IViewFor, INotifyPropertyChanged /// public object? ViewModel { get; set; } - /// - /// Gets or sets the first name text. - /// + /// Gets or sets the first name text. public string FirstNameText { get => _firstNameText; @@ -46,9 +38,7 @@ public string FirstNameText } } - /// - /// Gets or sets the last name text. - /// + /// Gets or sets the last name text. public string LastNameText { get => _lastNameText; diff --git a/src/tests/SharedScenarios/OneWayBind/TwoSameTypeBindings/MyViewModel.cs b/src/tests/SharedScenarios/OneWayBind/TwoSameTypeBindings/MyViewModel.cs index e692166..88f41c7 100644 --- a/src/tests/SharedScenarios/OneWayBind/TwoSameTypeBindings/MyViewModel.cs +++ b/src/tests/SharedScenarios/OneWayBind/TwoSameTypeBindings/MyViewModel.cs @@ -6,27 +6,19 @@ namespace SharedScenarios.OneWayBind.TwoSameTypeBindings; -/// -/// Source ViewModel with two string properties to test same-type-signature grouping. -/// +/// Source ViewModel with two string properties to test same-type-signature grouping. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _firstName = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private string _lastName = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the first name. - /// + /// Gets or sets the first name. public string FirstName { get => _firstName; @@ -42,9 +34,7 @@ public string FirstName } } - /// - /// Gets or sets the last name. - /// + /// Gets or sets the last name. public string LastName { get => _lastName; diff --git a/src/tests/SharedScenarios/OneWayBind/TwoSameTypeBindings/Scenario.cs b/src/tests/SharedScenarios/OneWayBind/TwoSameTypeBindings/Scenario.cs index 9bd89df..1a06114 100644 --- a/src/tests/SharedScenarios/OneWayBind/TwoSameTypeBindings/Scenario.cs +++ b/src/tests/SharedScenarios/OneWayBind/TwoSameTypeBindings/Scenario.cs @@ -19,9 +19,9 @@ public static class Scenario /// The target view. /// The source view model. /// A tuple of bindings. - public static (IReactiveBinding first, IReactiveBinding last) Execute( + public static (IReactiveBinding first, IReactiveBinding last) Execute( MyView view, - MyViewModel vm) - => (view.OneWayBind(vm, x => x.FirstName, x => x.FirstNameText), + MyViewModel vm) => + (view.OneWayBind(vm, x => x.FirstName, x => x.FirstNameText), view.OneWayBind(vm, x => x.LastName, x => x.LastNameText)); } diff --git a/src/tests/SharedScenarios/WhenAny/DeepPropertyChain/ChildModel.cs b/src/tests/SharedScenarios/WhenAny/DeepPropertyChain/ChildModel.cs index fb7640e..4313e29 100644 --- a/src/tests/SharedScenarios/WhenAny/DeepPropertyChain/ChildModel.cs +++ b/src/tests/SharedScenarios/WhenAny/DeepPropertyChain/ChildModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.WhenAny.DeepPropertyChain; -/// -/// Child model with a name property. -/// +/// Child model with a name property. public class ChildModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; diff --git a/src/tests/SharedScenarios/WhenAny/DeepPropertyChain/ParentViewModel.cs b/src/tests/SharedScenarios/WhenAny/DeepPropertyChain/ParentViewModel.cs index 92fe419..42c464f 100644 --- a/src/tests/SharedScenarios/WhenAny/DeepPropertyChain/ParentViewModel.cs +++ b/src/tests/SharedScenarios/WhenAny/DeepPropertyChain/ParentViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.WhenAny.DeepPropertyChain; -/// -/// Parent ViewModel containing a child model. -/// +/// Parent ViewModel containing a child model. public class ParentViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private ChildModel _child = new ChildModel(); /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the child model. - /// + /// Gets or sets the child model. public ChildModel Child { get => _child; diff --git a/src/tests/SharedScenarios/WhenAny/DeepPropertyChain/Scenario.cs b/src/tests/SharedScenarios/WhenAny/DeepPropertyChain/Scenario.cs index 9c0e100..deb2372 100644 --- a/src/tests/SharedScenarios/WhenAny/DeepPropertyChain/Scenario.cs +++ b/src/tests/SharedScenarios/WhenAny/DeepPropertyChain/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenAny.DeepPropertyChain; -/// -/// Exercises WhenAny with a deep property chain (x => x.Child.Name). -/// +/// Exercises WhenAny with a deep property chain (x => x.Child.Name). public static class Scenario { - /// - /// Creates a WhenAny observable for Child.Name via IObservedChange. - /// + /// Creates a WhenAny observable for Child.Name via IObservedChange. /// The parent view model to observe. /// An observable of name values from the child. - public static IObservable Execute(ParentViewModel vm) - => vm.WhenAny(x => x.Child.Name, c => c.Value); + public static IObservable Execute(ParentViewModel vm) => + vm.WhenAny(x => x.Child.Name, c => c.Value); } diff --git a/src/tests/SharedScenarios/WhenAny/MultiPropertyDeepChain/ChildModel.cs b/src/tests/SharedScenarios/WhenAny/MultiPropertyDeepChain/ChildModel.cs index 02bb465..d2d34d7 100644 --- a/src/tests/SharedScenarios/WhenAny/MultiPropertyDeepChain/ChildModel.cs +++ b/src/tests/SharedScenarios/WhenAny/MultiPropertyDeepChain/ChildModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.WhenAny.MultiPropertyDeepChain; -/// -/// Child model with a name property. -/// +/// Child model with a name property. public class ChildModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; diff --git a/src/tests/SharedScenarios/WhenAny/MultiPropertyDeepChain/ParentViewModel.cs b/src/tests/SharedScenarios/WhenAny/MultiPropertyDeepChain/ParentViewModel.cs index e487f8e..d987b42 100644 --- a/src/tests/SharedScenarios/WhenAny/MultiPropertyDeepChain/ParentViewModel.cs +++ b/src/tests/SharedScenarios/WhenAny/MultiPropertyDeepChain/ParentViewModel.cs @@ -6,27 +6,19 @@ namespace SharedScenarios.WhenAny.MultiPropertyDeepChain; -/// -/// Parent ViewModel containing a child model and a direct property. -/// +/// Parent ViewModel containing a child model and a direct property. public class ParentViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private ChildModel _child = new ChildModel(); - /// - /// The backing field for . - /// + /// The backing field for . private string _title = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the child model. - /// + /// Gets or sets the child model. public ChildModel Child { get => _child; @@ -42,9 +34,7 @@ public ChildModel Child } } - /// - /// Gets or sets the title. - /// + /// Gets or sets the title. public string Title { get => _title; diff --git a/src/tests/SharedScenarios/WhenAny/MultiPropertyDeepChain/Scenario.cs b/src/tests/SharedScenarios/WhenAny/MultiPropertyDeepChain/Scenario.cs index 43d0951..5afdb24 100644 --- a/src/tests/SharedScenarios/WhenAny/MultiPropertyDeepChain/Scenario.cs +++ b/src/tests/SharedScenarios/WhenAny/MultiPropertyDeepChain/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenAny.MultiPropertyDeepChain; -/// -/// Exercises WhenAny with multiple properties where one is a deep chain. -/// +/// Exercises WhenAny with multiple properties where one is a deep chain. public static class Scenario { - /// - /// Creates a WhenAny observable combining a deep chain (Child.Name) and a shallow property (Title). - /// + /// Creates a WhenAny observable combining a deep chain (Child.Name) and a shallow property (Title). /// The parent view model to observe. /// An observable of combined name and title strings. - public static IObservable Execute(ParentViewModel vm) - => vm.WhenAny(x => x.Child.Name, x => x.Title, (c1, c2) => $"{c1.Value} - {c2.Value}"); + public static IObservable Execute(ParentViewModel vm) => + vm.WhenAny(x => x.Child.Name, x => x.Title, (c1, c2) => $"{c1.Value} - {c2.Value}"); } diff --git a/src/tests/SharedScenarios/WhenAny/MultiPropertyTwoProperties/MyViewModel.cs b/src/tests/SharedScenarios/WhenAny/MultiPropertyTwoProperties/MyViewModel.cs index d4091db..30e9ced 100644 --- a/src/tests/SharedScenarios/WhenAny/MultiPropertyTwoProperties/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenAny/MultiPropertyTwoProperties/MyViewModel.cs @@ -6,27 +6,19 @@ namespace SharedScenarios.WhenAny.MultiPropertyTwoProperties; -/// -/// ViewModel with first and last name properties. -/// +/// ViewModel with first and last name properties. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _firstName = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private string _lastName = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the first name. - /// + /// Gets or sets the first name. public string FirstName { get => _firstName; @@ -42,9 +34,7 @@ public string FirstName } } - /// - /// Gets or sets the last name. - /// + /// Gets or sets the last name. public string LastName { get => _lastName; diff --git a/src/tests/SharedScenarios/WhenAny/MultiPropertyTwoProperties/Scenario.cs b/src/tests/SharedScenarios/WhenAny/MultiPropertyTwoProperties/Scenario.cs index 4a89106..531cdb3 100644 --- a/src/tests/SharedScenarios/WhenAny/MultiPropertyTwoProperties/Scenario.cs +++ b/src/tests/SharedScenarios/WhenAny/MultiPropertyTwoProperties/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenAny.MultiPropertyTwoProperties; -/// -/// Exercises WhenAny with two properties and a selector combining IObservedChange values. -/// +/// Exercises WhenAny with two properties and a selector combining IObservedChange values. public static class Scenario { - /// - /// Creates a WhenAny observable combining FirstName and LastName via IObservedChange. - /// + /// Creates a WhenAny observable combining FirstName and LastName via IObservedChange. /// The view model to observe. /// An observable of combined name strings. - public static IObservable Execute(MyViewModel vm) - => vm.WhenAny(x => x.FirstName, x => x.LastName, (c1, c2) => $"{c1.Value} {c2.Value}"); + public static IObservable Execute(MyViewModel vm) => + vm.WhenAny(x => x.FirstName, x => x.LastName, (c1, c2) => $"{c1.Value} {c2.Value}"); } diff --git a/src/tests/SharedScenarios/WhenAny/MultipleInvocationsSameType/MyViewModel.cs b/src/tests/SharedScenarios/WhenAny/MultipleInvocationsSameType/MyViewModel.cs index cefab1b..ded6aa7 100644 --- a/src/tests/SharedScenarios/WhenAny/MultipleInvocationsSameType/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenAny/MultipleInvocationsSameType/MyViewModel.cs @@ -6,27 +6,19 @@ namespace SharedScenarios.WhenAny.MultipleInvocationsSameType; -/// -/// ViewModel with two string properties for testing multiple same-type WhenAny invocations. -/// +/// ViewModel with two string properties for testing multiple same-type WhenAny invocations. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _firstName = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private string _lastName = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the first name. - /// + /// Gets or sets the first name. public string FirstName { get => _firstName; @@ -42,9 +34,7 @@ public string FirstName } } - /// - /// Gets or sets the last name. - /// + /// Gets or sets the last name. public string LastName { get => _lastName; diff --git a/src/tests/SharedScenarios/WhenAny/MultipleInvocationsSameType/Scenario.cs b/src/tests/SharedScenarios/WhenAny/MultipleInvocationsSameType/Scenario.cs index 3797599..f077d39 100644 --- a/src/tests/SharedScenarios/WhenAny/MultipleInvocationsSameType/Scenario.cs +++ b/src/tests/SharedScenarios/WhenAny/MultipleInvocationsSameType/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenAny.MultipleInvocationsSameType; -/// -/// Exercises multiple WhenAny invocations with the same type signature to test else-if dispatch. -/// +/// Exercises multiple WhenAny invocations with the same type signature to test else-if dispatch. public static class Scenario { - /// - /// Creates two WhenAny observables with the same type signature (MyViewModel, string, string). - /// + /// Creates two WhenAny observables with the same type signature (MyViewModel, string, string). /// The view model to observe. /// A tuple of observables for first name and last name. - public static (IObservable FirstObs, IObservable LastObs) Execute(MyViewModel vm) - => (vm.WhenAny(x => x.FirstName, c => c.Value), vm.WhenAny(x => x.LastName, c => c.Value)); + public static (IObservable FirstObs, IObservable LastObs) Execute(MyViewModel vm) => + (vm.WhenAny(x => x.FirstName, c => c.Value), vm.WhenAny(x => x.LastName, c => c.Value)); } diff --git a/src/tests/SharedScenarios/WhenAny/SinglePropertyINPC/MyViewModel.cs b/src/tests/SharedScenarios/WhenAny/SinglePropertyINPC/MyViewModel.cs index 6da315c..60884f5 100644 --- a/src/tests/SharedScenarios/WhenAny/SinglePropertyINPC/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenAny/SinglePropertyINPC/MyViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.WhenAny.SinglePropertyINPC; -/// -/// ViewModel implementing INotifyPropertyChanged with a single string property. -/// +/// ViewModel implementing INotifyPropertyChanged with a single string property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; diff --git a/src/tests/SharedScenarios/WhenAny/SinglePropertyINPC/Scenario.cs b/src/tests/SharedScenarios/WhenAny/SinglePropertyINPC/Scenario.cs index 568a39f..47eeae5 100644 --- a/src/tests/SharedScenarios/WhenAny/SinglePropertyINPC/Scenario.cs +++ b/src/tests/SharedScenarios/WhenAny/SinglePropertyINPC/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenAny.SinglePropertyINPC; -/// -/// Exercises WhenAny on a single INPC property with a selector. -/// +/// Exercises WhenAny on a single INPC property with a selector. public static class Scenario { - /// - /// Creates a WhenAny observable for the Name property, extracting the value from IObservedChange. - /// + /// Creates a WhenAny observable for the Name property, extracting the value from IObservedChange. /// The view model to observe. /// An observable of name values. - public static IObservable Execute(MyViewModel vm) - => vm.WhenAny(x => x.Name, c => c.Value); + public static IObservable Execute(MyViewModel vm) => + vm.WhenAny(x => x.Name, c => c.Value); } diff --git a/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableCombineLatest/ChildModel.cs b/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableCombineLatest/ChildModel.cs index ec19242..15b6b5f 100644 --- a/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableCombineLatest/ChildModel.cs +++ b/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableCombineLatest/ChildModel.cs @@ -7,27 +7,19 @@ namespace SharedScenarios.WhenAnyObservable.DeepObservableCombineLatest; -/// -/// Child model with two observable properties of different types. -/// +/// Child model with two observable properties of different types. public class ChildModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private IObservable? _count; - /// - /// The backing field for . - /// + /// The backing field for . private IObservable? _message; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the count observable. - /// + /// Gets or sets the count observable. public IObservable? Count { get => _count; @@ -43,9 +35,7 @@ public IObservable? Count } } - /// - /// Gets or sets the message observable. - /// + /// Gets or sets the message observable. public IObservable? Message { get => _message; diff --git a/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableCombineLatest/ParentViewModel.cs b/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableCombineLatest/ParentViewModel.cs index 5952f03..9dd5aa2 100644 --- a/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableCombineLatest/ParentViewModel.cs +++ b/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableCombineLatest/ParentViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.WhenAnyObservable.DeepObservableCombineLatest; -/// -/// Parent ViewModel containing a child model with observable properties. -/// +/// Parent ViewModel containing a child model with observable properties. public class ParentViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private ChildModel _child = new ChildModel(); /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the child model. - /// + /// Gets or sets the child model. public ChildModel Child { get => _child; diff --git a/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableCombineLatest/Scenario.cs b/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableCombineLatest/Scenario.cs index d570fad..08b4951 100644 --- a/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableCombineLatest/Scenario.cs +++ b/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableCombineLatest/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenAnyObservable.DeepObservableCombineLatest; -/// -/// Exercises WhenAnyObservable with deep property chains and a selector (CombineLatest pattern). -/// +/// Exercises WhenAnyObservable with deep property chains and a selector (CombineLatest pattern). public static class Scenario { - /// - /// Creates a WhenAnyObservable that combines two deep observable properties using a selector. - /// + /// Creates a WhenAnyObservable that combines two deep observable properties using a selector. /// The parent view model to observe. /// An observable that combines values from both deep observable properties. - public static IObservable Execute(ParentViewModel vm) - => vm.WhenAnyObservable(x => x.Child.Count, x => x.Child.Message, (count, message) => $"{message}: {count}"); + public static IObservable Execute(ParentViewModel vm) => + vm.WhenAnyObservable(x => x.Child.Count, x => x.Child.Message, (count, message) => $"{message}: {count}"); } diff --git a/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableMerge/ChildModel.cs b/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableMerge/ChildModel.cs index 9410c5d..7401cec 100644 --- a/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableMerge/ChildModel.cs +++ b/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableMerge/ChildModel.cs @@ -7,27 +7,19 @@ namespace SharedScenarios.WhenAnyObservable.DeepObservableMerge; -/// -/// Child model with two observable properties of the same type. -/// +/// Child model with two observable properties of the same type. public class ChildModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private IObservable? _command1; - /// - /// The backing field for . - /// + /// The backing field for . private IObservable? _command2; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the first command observable. - /// + /// Gets or sets the first command observable. public IObservable? Command1 { get => _command1; @@ -43,9 +35,7 @@ public IObservable? Command1 } } - /// - /// Gets or sets the second command observable. - /// + /// Gets or sets the second command observable. public IObservable? Command2 { get => _command2; diff --git a/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableMerge/ParentViewModel.cs b/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableMerge/ParentViewModel.cs index be551bb..0474869 100644 --- a/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableMerge/ParentViewModel.cs +++ b/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableMerge/ParentViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.WhenAnyObservable.DeepObservableMerge; -/// -/// Parent ViewModel containing a child model with observable properties. -/// +/// Parent ViewModel containing a child model with observable properties. public class ParentViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private ChildModel _child = new ChildModel(); /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the child model. - /// + /// Gets or sets the child model. public ChildModel Child { get => _child; diff --git a/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableMerge/Scenario.cs b/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableMerge/Scenario.cs index dad3e04..5dbcf3c 100644 --- a/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableMerge/Scenario.cs +++ b/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableMerge/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenAnyObservable.DeepObservableMerge; -/// -/// Exercises WhenAnyObservable with deep property chains in a merge pattern. -/// +/// Exercises WhenAnyObservable with deep property chains in a merge pattern. public static class Scenario { - /// - /// Creates a WhenAnyObservable that merges two deep observable properties. - /// + /// Creates a WhenAnyObservable that merges two deep observable properties. /// The parent view model to observe. /// An observable that merges values from both deep observable properties. - public static IObservable Execute(ParentViewModel vm) - => vm.WhenAnyObservable(x => x.Child.Command1, x => x.Child.Command2); + public static IObservable Execute(ParentViewModel vm) => + vm.WhenAnyObservable(x => x.Child.Command1, x => x.Child.Command2); } diff --git a/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableSwitch/ChildModel.cs b/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableSwitch/ChildModel.cs index 87d1ebe..dc05319 100644 --- a/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableSwitch/ChildModel.cs +++ b/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableSwitch/ChildModel.cs @@ -7,22 +7,16 @@ namespace SharedScenarios.WhenAnyObservable.DeepObservableSwitch; -/// -/// Child model with an observable property. -/// +/// Child model with an observable property. public class ChildModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private IObservable? _myCommand; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the command observable. - /// + /// Gets or sets the command observable. public IObservable? MyCommand { get => _myCommand; diff --git a/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableSwitch/ParentViewModel.cs b/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableSwitch/ParentViewModel.cs index 74c6a6e..fd84caa 100644 --- a/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableSwitch/ParentViewModel.cs +++ b/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableSwitch/ParentViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.WhenAnyObservable.DeepObservableSwitch; -/// -/// Parent ViewModel containing a child model with an observable property. -/// +/// Parent ViewModel containing a child model with an observable property. public class ParentViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private ChildModel _child = new ChildModel(); /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the child model. - /// + /// Gets or sets the child model. public ChildModel Child { get => _child; diff --git a/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableSwitch/Scenario.cs b/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableSwitch/Scenario.cs index 1f78ee3..b4f5b0a 100644 --- a/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableSwitch/Scenario.cs +++ b/src/tests/SharedScenarios/WhenAnyObservable/DeepObservableSwitch/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenAnyObservable.DeepObservableSwitch; -/// -/// Exercises WhenAnyObservable with a deep property chain (x => x.Child.MyCommand). -/// +/// Exercises WhenAnyObservable with a deep property chain (x => x.Child.MyCommand). public static class Scenario { - /// - /// Creates a WhenAnyObservable that switches to the latest value of Child.MyCommand. - /// + /// Creates a WhenAnyObservable that switches to the latest value of Child.MyCommand. /// The parent view model to observe. /// An observable that switches to the latest Child.MyCommand observable. - public static IObservable Execute(ParentViewModel vm) - => vm.WhenAnyObservable(x => x.Child.MyCommand); + public static IObservable Execute(ParentViewModel vm) => + vm.WhenAnyObservable(x => x.Child.MyCommand); } diff --git a/src/tests/SharedScenarios/WhenAnyObservable/MultipleInvocationsSameType/MyViewModel.cs b/src/tests/SharedScenarios/WhenAnyObservable/MultipleInvocationsSameType/MyViewModel.cs index 3713ec1..e1443b2 100644 --- a/src/tests/SharedScenarios/WhenAnyObservable/MultipleInvocationsSameType/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenAnyObservable/MultipleInvocationsSameType/MyViewModel.cs @@ -7,27 +7,19 @@ namespace SharedScenarios.WhenAnyObservable.MultipleInvocationsSameType; -/// -/// ViewModel with two observable string properties for testing multiple same-type WhenAnyObservable invocations. -/// +/// ViewModel with two observable string properties for testing multiple same-type WhenAnyObservable invocations. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private IObservable? _command1; - /// - /// The backing field for . - /// + /// The backing field for . private IObservable? _command2; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the first command observable. - /// + /// Gets or sets the first command observable. public IObservable? Command1 { get => _command1; @@ -43,9 +35,7 @@ public IObservable? Command1 } } - /// - /// Gets or sets the second command observable. - /// + /// Gets or sets the second command observable. public IObservable? Command2 { get => _command2; diff --git a/src/tests/SharedScenarios/WhenAnyObservable/MultipleInvocationsSameType/Scenario.cs b/src/tests/SharedScenarios/WhenAnyObservable/MultipleInvocationsSameType/Scenario.cs index 185e18e..d27fdd2 100644 --- a/src/tests/SharedScenarios/WhenAnyObservable/MultipleInvocationsSameType/Scenario.cs +++ b/src/tests/SharedScenarios/WhenAnyObservable/MultipleInvocationsSameType/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenAnyObservable.MultipleInvocationsSameType; -/// -/// Exercises multiple WhenAnyObservable invocations with the same type signature to test else-if dispatch. -/// +/// Exercises multiple WhenAnyObservable invocations with the same type signature to test else-if dispatch. public static class Scenario { - /// - /// Creates two WhenAnyObservable calls on the same VM with the same type signature. - /// + /// Creates two WhenAnyObservable calls on the same VM with the same type signature. /// The view model to observe. /// A tuple of observables for each command. - public static (IObservable Cmd1Obs, IObservable Cmd2Obs) Execute(MyViewModel vm) - => (vm.WhenAnyObservable(x => x.Command1), vm.WhenAnyObservable(x => x.Command2)); + public static (IObservable Cmd1Obs, IObservable Cmd2Obs) Execute(MyViewModel vm) => + (vm.WhenAnyObservable(x => x.Command1), vm.WhenAnyObservable(x => x.Command2)); } diff --git a/src/tests/SharedScenarios/WhenAnyObservable/SingleObservable/MyViewModel.cs b/src/tests/SharedScenarios/WhenAnyObservable/SingleObservable/MyViewModel.cs index 3f498b9..b69f5aa 100644 --- a/src/tests/SharedScenarios/WhenAnyObservable/SingleObservable/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenAnyObservable/SingleObservable/MyViewModel.cs @@ -7,22 +7,16 @@ namespace SharedScenarios.WhenAnyObservable.SingleObservable; -/// -/// ViewModel implementing INotifyPropertyChanged with a property that is itself an observable. -/// +/// ViewModel implementing INotifyPropertyChanged with a property that is itself an observable. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private IObservable? _myCommand; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the command observable. - /// + /// Gets or sets the command observable. public IObservable? MyCommand { get => _myCommand; diff --git a/src/tests/SharedScenarios/WhenAnyObservable/SingleObservable/Scenario.cs b/src/tests/SharedScenarios/WhenAnyObservable/SingleObservable/Scenario.cs index 4312f3e..b6b1240 100644 --- a/src/tests/SharedScenarios/WhenAnyObservable/SingleObservable/Scenario.cs +++ b/src/tests/SharedScenarios/WhenAnyObservable/SingleObservable/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenAnyObservable.SingleObservable; -/// -/// Exercises WhenAnyObservable on a single observable property. -/// +/// Exercises WhenAnyObservable on a single observable property. public static class Scenario { - /// - /// Creates a WhenAnyObservable that switches to the latest value of MyCommand. - /// + /// Creates a WhenAnyObservable that switches to the latest value of MyCommand. /// The view model to observe. /// An observable that switches to the latest MyCommand observable. - public static IObservable Execute(MyViewModel vm) - => vm.WhenAnyObservable(x => x.MyCommand); + public static IObservable Execute(MyViewModel vm) => + vm.WhenAnyObservable(x => x.MyCommand); } diff --git a/src/tests/SharedScenarios/WhenAnyObservable/TwoObservablesMerge/MyViewModel.cs b/src/tests/SharedScenarios/WhenAnyObservable/TwoObservablesMerge/MyViewModel.cs index 1cc0b58..a6676ac 100644 --- a/src/tests/SharedScenarios/WhenAnyObservable/TwoObservablesMerge/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenAnyObservable/TwoObservablesMerge/MyViewModel.cs @@ -7,27 +7,19 @@ namespace SharedScenarios.WhenAnyObservable.TwoObservablesMerge; -/// -/// ViewModel with two observable properties of the same type. -/// +/// ViewModel with two observable properties of the same type. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private IObservable? _command1; - /// - /// The backing field for . - /// + /// The backing field for . private IObservable? _command2; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the first command observable. - /// + /// Gets or sets the first command observable. public IObservable? Command1 { get => _command1; @@ -43,9 +35,7 @@ public IObservable? Command1 } } - /// - /// Gets or sets the second command observable. - /// + /// Gets or sets the second command observable. public IObservable? Command2 { get => _command2; diff --git a/src/tests/SharedScenarios/WhenAnyObservable/TwoObservablesMerge/Scenario.cs b/src/tests/SharedScenarios/WhenAnyObservable/TwoObservablesMerge/Scenario.cs index 259f532..ab5bfc7 100644 --- a/src/tests/SharedScenarios/WhenAnyObservable/TwoObservablesMerge/Scenario.cs +++ b/src/tests/SharedScenarios/WhenAnyObservable/TwoObservablesMerge/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenAnyObservable.TwoObservablesMerge; -/// -/// Exercises WhenAnyObservable on two observable properties of the same type (merge pattern). -/// +/// Exercises WhenAnyObservable on two observable properties of the same type (merge pattern). public static class Scenario { - /// - /// Creates a WhenAnyObservable that merges the two command observables. - /// + /// Creates a WhenAnyObservable that merges the two command observables. /// The view model to observe. /// An observable that merges values from both command observables. - public static IObservable Execute(MyViewModel vm) - => vm.WhenAnyObservable(x => x.Command1, x => x.Command2); + public static IObservable Execute(MyViewModel vm) => + vm.WhenAnyObservable(x => x.Command1, x => x.Command2); } diff --git a/src/tests/SharedScenarios/WhenAnyObservable/TwoObservablesWithSelector/MyViewModel.cs b/src/tests/SharedScenarios/WhenAnyObservable/TwoObservablesWithSelector/MyViewModel.cs index 3e343ad..61d6cae 100644 --- a/src/tests/SharedScenarios/WhenAnyObservable/TwoObservablesWithSelector/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenAnyObservable/TwoObservablesWithSelector/MyViewModel.cs @@ -7,27 +7,19 @@ namespace SharedScenarios.WhenAnyObservable.TwoObservablesWithSelector; -/// -/// ViewModel with two observable properties of different types. -/// +/// ViewModel with two observable properties of different types. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private IObservable? _count; - /// - /// The backing field for . - /// + /// The backing field for . private IObservable? _message; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the count observable. - /// + /// Gets or sets the count observable. public IObservable? Count { get => _count; @@ -43,9 +35,7 @@ public IObservable? Count } } - /// - /// Gets or sets the message observable. - /// + /// Gets or sets the message observable. public IObservable? Message { get => _message; diff --git a/src/tests/SharedScenarios/WhenAnyObservable/TwoObservablesWithSelector/Scenario.cs b/src/tests/SharedScenarios/WhenAnyObservable/TwoObservablesWithSelector/Scenario.cs index 60912b1..f91e544 100644 --- a/src/tests/SharedScenarios/WhenAnyObservable/TwoObservablesWithSelector/Scenario.cs +++ b/src/tests/SharedScenarios/WhenAnyObservable/TwoObservablesWithSelector/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenAnyObservable.TwoObservablesWithSelector; -/// -/// Exercises WhenAnyObservable on two observable properties with different types and a selector (CombineLatest pattern). -/// +/// Exercises WhenAnyObservable on two observable properties with different types and a selector (CombineLatest pattern). public static class Scenario { - /// - /// Creates a WhenAnyObservable that combines the two observable properties using a selector. - /// + /// Creates a WhenAnyObservable that combines the two observable properties using a selector. /// The view model to observe. /// An observable that combines values from both observable properties. - public static IObservable Execute(MyViewModel vm) - => vm.WhenAnyObservable(x => x.Count, x => x.Message, (count, message) => $"{message}: {count}"); + public static IObservable Execute(MyViewModel vm) => + vm.WhenAnyObservable(x => x.Count, x => x.Message, (count, message) => $"{message}: {count}"); } diff --git a/src/tests/SharedScenarios/WhenAnyValue/DeepPropertyChain/ChildModel.cs b/src/tests/SharedScenarios/WhenAnyValue/DeepPropertyChain/ChildModel.cs index 60e8f8d..995632f 100644 --- a/src/tests/SharedScenarios/WhenAnyValue/DeepPropertyChain/ChildModel.cs +++ b/src/tests/SharedScenarios/WhenAnyValue/DeepPropertyChain/ChildModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.WhenAnyValue.DeepPropertyChain; -/// -/// Child model with a name property. -/// +/// Child model with a name property. public class ChildModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; diff --git a/src/tests/SharedScenarios/WhenAnyValue/DeepPropertyChain/ParentViewModel.cs b/src/tests/SharedScenarios/WhenAnyValue/DeepPropertyChain/ParentViewModel.cs index 89117a3..fd57fd8 100644 --- a/src/tests/SharedScenarios/WhenAnyValue/DeepPropertyChain/ParentViewModel.cs +++ b/src/tests/SharedScenarios/WhenAnyValue/DeepPropertyChain/ParentViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.WhenAnyValue.DeepPropertyChain; -/// -/// Parent ViewModel containing a child model. -/// +/// Parent ViewModel containing a child model. public class ParentViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private ChildModel _child = new ChildModel(); /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the child model. - /// + /// Gets or sets the child model. public ChildModel Child { get => _child; diff --git a/src/tests/SharedScenarios/WhenAnyValue/DeepPropertyChain/Scenario.cs b/src/tests/SharedScenarios/WhenAnyValue/DeepPropertyChain/Scenario.cs index 5abdfcb..33bd42b 100644 --- a/src/tests/SharedScenarios/WhenAnyValue/DeepPropertyChain/Scenario.cs +++ b/src/tests/SharedScenarios/WhenAnyValue/DeepPropertyChain/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenAnyValue.DeepPropertyChain; -/// -/// Exercises WhenAnyValue with a deep property chain. -/// +/// Exercises WhenAnyValue with a deep property chain. public static class Scenario { - /// - /// Creates a WhenAnyValue observable for Child.Name. - /// + /// Creates a WhenAnyValue observable for Child.Name. /// The parent view model to observe. /// An observable of name values from the child. - public static IObservable Execute(ParentViewModel vm) - => vm.WhenAnyValue(x => x.Child.Name); + public static IObservable Execute(ParentViewModel vm) => + vm.WhenAnyValue(x => x.Child.Name); } diff --git a/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyFiveProperties/MyViewModel.cs b/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyFiveProperties/MyViewModel.cs index e06f40a..423103e 100644 --- a/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyFiveProperties/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyFiveProperties/MyViewModel.cs @@ -6,42 +6,28 @@ namespace SharedScenarios.WhenAnyValue.MultiPropertyFiveProperties; -/// -/// ViewModel with five observable properties. -/// +/// ViewModel with five observable properties. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _prop1 = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private int _prop2; - /// - /// The backing field for . - /// + /// The backing field for . private double _prop3; - /// - /// The backing field for . - /// + /// The backing field for . private bool _prop4; - /// - /// The backing field for . - /// + /// The backing field for . private string _prop5 = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets property 1. - /// + /// Gets or sets property 1. public string Prop1 { get => _prop1; @@ -57,9 +43,7 @@ public string Prop1 } } - /// - /// Gets or sets property 2. - /// + /// Gets or sets property 2. public int Prop2 { get => _prop2; @@ -75,9 +59,7 @@ public int Prop2 } } - /// - /// Gets or sets property 3. - /// + /// Gets or sets property 3. public double Prop3 { get => _prop3; @@ -93,9 +75,7 @@ public double Prop3 } } - /// - /// Gets or sets a value indicating whether property 4 is set. - /// + /// Gets or sets a value indicating whether property 4 is set. public bool Prop4 { get => _prop4; @@ -111,9 +91,7 @@ public bool Prop4 } } - /// - /// Gets or sets property 5. - /// + /// Gets or sets property 5. public string Prop5 { get => _prop5; diff --git a/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyFiveProperties/Scenario.cs b/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyFiveProperties/Scenario.cs index e86305e..ae5cd7b 100644 --- a/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyFiveProperties/Scenario.cs +++ b/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyFiveProperties/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenAnyValue.MultiPropertyFiveProperties; -/// -/// Exercises WhenAnyValue with five properties. -/// +/// Exercises WhenAnyValue with five properties. public static class Scenario { - /// - /// Creates a WhenAnyValue observable for five properties. - /// + /// Creates a WhenAnyValue observable for five properties. /// The view model to observe. /// An observable of five-property tuples. - public static IObservable<(string Prop1, int Prop2, double Prop3, bool Prop4, string Prop5)> Execute(MyViewModel vm) - => vm.WhenAnyValue(x => x.Prop1, x => x.Prop2, x => x.Prop3, x => x.Prop4, x => x.Prop5); + public static IObservable<(string Prop1, int Prop2, double Prop3, bool Prop4, string Prop5)> Execute(MyViewModel vm) => + vm.WhenAnyValue(x => x.Prop1, x => x.Prop2, x => x.Prop3, x => x.Prop4, x => x.Prop5); } diff --git a/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyThreeProperties/MyViewModel.cs b/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyThreeProperties/MyViewModel.cs index f7aaa0d..73b65e1 100644 --- a/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyThreeProperties/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyThreeProperties/MyViewModel.cs @@ -6,32 +6,22 @@ namespace SharedScenarios.WhenAnyValue.MultiPropertyThreeProperties; -/// -/// ViewModel with three observable properties. -/// +/// ViewModel with three observable properties. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private int _age; - /// - /// The backing field for . - /// + /// The backing field for . private double _score; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; @@ -47,9 +37,7 @@ public string Name } } - /// - /// Gets or sets the age. - /// + /// Gets or sets the age. public int Age { get => _age; @@ -65,9 +53,7 @@ public int Age } } - /// - /// Gets or sets the score. - /// + /// Gets or sets the score. public double Score { get => _score; diff --git a/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyThreeProperties/Scenario.cs b/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyThreeProperties/Scenario.cs index 08f9643..06b3617 100644 --- a/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyThreeProperties/Scenario.cs +++ b/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyThreeProperties/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenAnyValue.MultiPropertyThreeProperties; -/// -/// Exercises WhenAnyValue with three properties returning a tuple. -/// +/// Exercises WhenAnyValue with three properties returning a tuple. public static class Scenario { - /// - /// Creates a WhenAnyValue observable for Name, Age, and Score. - /// + /// Creates a WhenAnyValue observable for Name, Age, and Score. /// The view model to observe. /// An observable of (name, age, score) tuples. - public static IObservable<(string Name, int Age, double Score)> Execute(MyViewModel vm) - => vm.WhenAnyValue(x => x.Name, x => x.Age, x => x.Score); + public static IObservable<(string Name, int Age, double Score)> Execute(MyViewModel vm) => + vm.WhenAnyValue(x => x.Name, x => x.Age, x => x.Score); } diff --git a/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyTwelveProperties/Scenario.cs b/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyTwelveProperties/Scenario.cs index 7fb24ed..03ef5fc 100644 --- a/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyTwelveProperties/Scenario.cs +++ b/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyTwelveProperties/Scenario.cs @@ -7,20 +7,16 @@ namespace SharedScenarios.WhenAnyValue.MultiPropertyTwelveProperties; -/// -/// Exercises WhenAnyValue with twelve properties (maximum standard overload). -/// +/// Exercises WhenAnyValue with twelve properties (maximum standard overload). public static class Scenario { - /// - /// Creates a WhenAnyValue observable for twelve properties. - /// + /// Creates a WhenAnyValue observable for twelve properties. /// The fixture to observe. /// An observable of twelve-property tuples. public static IObservable<(string V1, string V2, string V3, string V4, string V5, string V6, string V7, string V8, string V9, - string V10, string V11, string V12)> Execute(WhenAnyFixture fixture) - => fixture.WhenAnyValue( + string V10, string V11, string V12)> Execute(WhenAnyFixture fixture) => + fixture.WhenAnyValue( x => x.Value1, x => x.Value2, x => x.Value3, diff --git a/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyTwelveProperties/WhenAnyFixture.cs b/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyTwelveProperties/WhenAnyFixture.cs index bfa9e89..adb0775 100644 --- a/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyTwelveProperties/WhenAnyFixture.cs +++ b/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyTwelveProperties/WhenAnyFixture.cs @@ -6,77 +6,49 @@ namespace SharedScenarios.WhenAnyValue.MultiPropertyTwelveProperties; -/// -/// ViewModel with twelve observable properties (maximum standard overload). -/// +/// ViewModel with twelve observable properties (maximum standard overload). public class WhenAnyFixture : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _value1 = "1"; - /// - /// The backing field for . - /// + /// The backing field for . private string _value2 = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private string _value3 = "3"; - /// - /// The backing field for . - /// + /// The backing field for . private string _value4 = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private string _value5 = "5"; - /// - /// The backing field for . - /// + /// The backing field for . private string _value6 = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private string _value7 = "7"; - /// - /// The backing field for . - /// + /// The backing field for . private string _value8 = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private string _value9 = "9"; - /// - /// The backing field for . - /// + /// The backing field for . private string _value10 = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private string _value11 = "11"; - /// - /// The backing field for . - /// + /// The backing field for . private string _value12 = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets value 1. - /// + /// Gets or sets value 1. public string Value1 { get => _value1; @@ -92,9 +64,7 @@ public string Value1 } } - /// - /// Gets or sets value 2. - /// + /// Gets or sets value 2. public string Value2 { get => _value2; @@ -110,9 +80,7 @@ public string Value2 } } - /// - /// Gets or sets value 3. - /// + /// Gets or sets value 3. public string Value3 { get => _value3; @@ -128,9 +96,7 @@ public string Value3 } } - /// - /// Gets or sets value 4. - /// + /// Gets or sets value 4. public string Value4 { get => _value4; @@ -146,9 +112,7 @@ public string Value4 } } - /// - /// Gets or sets value 5. - /// + /// Gets or sets value 5. public string Value5 { get => _value5; @@ -164,9 +128,7 @@ public string Value5 } } - /// - /// Gets or sets value 6. - /// + /// Gets or sets value 6. public string Value6 { get => _value6; @@ -182,9 +144,7 @@ public string Value6 } } - /// - /// Gets or sets value 7. - /// + /// Gets or sets value 7. public string Value7 { get => _value7; @@ -200,9 +160,7 @@ public string Value7 } } - /// - /// Gets or sets value 8. - /// + /// Gets or sets value 8. public string Value8 { get => _value8; @@ -218,9 +176,7 @@ public string Value8 } } - /// - /// Gets or sets value 9. - /// + /// Gets or sets value 9. public string Value9 { get => _value9; @@ -236,9 +192,7 @@ public string Value9 } } - /// - /// Gets or sets value 10. - /// + /// Gets or sets value 10. public string Value10 { get => _value10; @@ -254,9 +208,7 @@ public string Value10 } } - /// - /// Gets or sets value 11. - /// + /// Gets or sets value 11. public string Value11 { get => _value11; @@ -272,9 +224,7 @@ public string Value11 } } - /// - /// Gets or sets value 12. - /// + /// Gets or sets value 12. public string Value12 { get => _value12; diff --git a/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyTwoProperties/MyViewModel.cs b/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyTwoProperties/MyViewModel.cs index 51e4a85..c71a0d4 100644 --- a/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyTwoProperties/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyTwoProperties/MyViewModel.cs @@ -6,27 +6,19 @@ namespace SharedScenarios.WhenAnyValue.MultiPropertyTwoProperties; -/// -/// ViewModel with two observable properties. -/// +/// ViewModel with two observable properties. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private int _age; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; @@ -42,9 +34,7 @@ public string Name } } - /// - /// Gets or sets the age. - /// + /// Gets or sets the age. public int Age { get => _age; diff --git a/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyTwoProperties/Scenario.cs b/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyTwoProperties/Scenario.cs index 639b2fd..24cd2c3 100644 --- a/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyTwoProperties/Scenario.cs +++ b/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyTwoProperties/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenAnyValue.MultiPropertyTwoProperties; -/// -/// Exercises WhenAnyValue with two properties returning a tuple. -/// +/// Exercises WhenAnyValue with two properties returning a tuple. public static class Scenario { - /// - /// Creates a WhenAnyValue observable for Name and Age. - /// + /// Creates a WhenAnyValue observable for Name and Age. /// The view model to observe. /// An observable of (name, age) tuples. - public static IObservable<(string Name, int Age)> Execute(MyViewModel vm) - => vm.WhenAnyValue(x => x.Name, x => x.Age); + public static IObservable<(string Name, int Age)> Execute(MyViewModel vm) => + vm.WhenAnyValue(x => x.Name, x => x.Age); } diff --git a/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyWithSelector/MyViewModel.cs b/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyWithSelector/MyViewModel.cs index 5d2a718..23c88d7 100644 --- a/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyWithSelector/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyWithSelector/MyViewModel.cs @@ -6,27 +6,19 @@ namespace SharedScenarios.WhenAnyValue.MultiPropertyWithSelector; -/// -/// ViewModel with first and last name properties. -/// +/// ViewModel with first and last name properties. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _firstName = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private string _lastName = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the first name. - /// + /// Gets or sets the first name. public string FirstName { get => _firstName; @@ -42,9 +34,7 @@ public string FirstName } } - /// - /// Gets or sets the last name. - /// + /// Gets or sets the last name. public string LastName { get => _lastName; diff --git a/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyWithSelector/Scenario.cs b/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyWithSelector/Scenario.cs index d539f31..fdf3b32 100644 --- a/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyWithSelector/Scenario.cs +++ b/src/tests/SharedScenarios/WhenAnyValue/MultiPropertyWithSelector/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenAnyValue.MultiPropertyWithSelector; -/// -/// Exercises WhenAnyValue with a selector function combining two properties. -/// +/// Exercises WhenAnyValue with a selector function combining two properties. public static class Scenario { - /// - /// Creates a WhenAnyValue observable combining FirstName and LastName. - /// + /// Creates a WhenAnyValue observable combining FirstName and LastName. /// The view model to observe. /// An observable of combined name strings. - public static IObservable Execute(MyViewModel vm) - => vm.WhenAnyValue(x => x.FirstName, x => x.LastName, (f, l) => $"{f} {l}"); + public static IObservable Execute(MyViewModel vm) => + vm.WhenAnyValue(x => x.FirstName, x => x.LastName, (f, l) => $"{f} {l}"); } diff --git a/src/tests/SharedScenarios/WhenAnyValue/NullableProperties/MyViewModel.cs b/src/tests/SharedScenarios/WhenAnyValue/NullableProperties/MyViewModel.cs index 32e0012..3d0aff5 100644 --- a/src/tests/SharedScenarios/WhenAnyValue/NullableProperties/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenAnyValue/NullableProperties/MyViewModel.cs @@ -6,27 +6,19 @@ namespace SharedScenarios.WhenAnyValue.NullableProperties; -/// -/// ViewModel with nullable properties. -/// +/// ViewModel with nullable properties. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string? _nullableName; - /// - /// The backing field for . - /// + /// The backing field for . private int? _nullableAge; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the nullable name. - /// + /// Gets or sets the nullable name. public string? NullableName { get => _nullableName; @@ -42,9 +34,7 @@ public string? NullableName } } - /// - /// Gets or sets the nullable age. - /// + /// Gets or sets the nullable age. public int? NullableAge { get => _nullableAge; diff --git a/src/tests/SharedScenarios/WhenAnyValue/NullableProperties/Scenario.cs b/src/tests/SharedScenarios/WhenAnyValue/NullableProperties/Scenario.cs index 67dd336..3f05d54 100644 --- a/src/tests/SharedScenarios/WhenAnyValue/NullableProperties/Scenario.cs +++ b/src/tests/SharedScenarios/WhenAnyValue/NullableProperties/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenAnyValue.NullableProperties; -/// -/// Exercises WhenAnyValue with nullable property types. -/// +/// Exercises WhenAnyValue with nullable property types. public static class Scenario { - /// - /// Creates WhenAnyValue observables for nullable properties. - /// + /// Creates WhenAnyValue observables for nullable properties. /// The view model to observe. /// A tuple of observables for nullable name and age. - public static (IObservable NameObs, IObservable AgeObs) Execute(MyViewModel vm) - => (vm.WhenAnyValue(x => x.NullableName!), vm.WhenAnyValue(x => x.NullableAge!)); + public static (IObservable NameObs, IObservable AgeObs) Execute(MyViewModel vm) => + (vm.WhenAnyValue(x => x.NullableName!), vm.WhenAnyValue(x => x.NullableAge!)); } diff --git a/src/tests/SharedScenarios/WhenAnyValue/SinglePropertyINPC/MyViewModel.cs b/src/tests/SharedScenarios/WhenAnyValue/SinglePropertyINPC/MyViewModel.cs index ba433f3..1680a07 100644 --- a/src/tests/SharedScenarios/WhenAnyValue/SinglePropertyINPC/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenAnyValue/SinglePropertyINPC/MyViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.WhenAnyValue.SinglePropertyINPC; -/// -/// ViewModel implementing INotifyPropertyChanged with a single string property. -/// +/// ViewModel implementing INotifyPropertyChanged with a single string property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; diff --git a/src/tests/SharedScenarios/WhenAnyValue/SinglePropertyINPC/Scenario.cs b/src/tests/SharedScenarios/WhenAnyValue/SinglePropertyINPC/Scenario.cs index 9ca9b6d..c239b05 100644 --- a/src/tests/SharedScenarios/WhenAnyValue/SinglePropertyINPC/Scenario.cs +++ b/src/tests/SharedScenarios/WhenAnyValue/SinglePropertyINPC/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenAnyValue.SinglePropertyINPC; -/// -/// Exercises WhenAnyValue on a single INPC property. -/// +/// Exercises WhenAnyValue on a single INPC property. public static class Scenario { - /// - /// Creates a WhenAnyValue observable for the Name property. - /// + /// Creates a WhenAnyValue observable for the Name property. /// The view model to observe. /// An observable of name values. - public static IObservable Execute(MyViewModel vm) - => vm.WhenAnyValue(x => x.Name); + public static IObservable Execute(MyViewModel vm) => + vm.WhenAnyValue(x => x.Name); } diff --git a/src/tests/SharedScenarios/WhenAnyValue/SinglePropertyReactiveObject/MyViewModel.cs b/src/tests/SharedScenarios/WhenAnyValue/SinglePropertyReactiveObject/MyViewModel.cs index 1ccaee5..51496cc 100644 --- a/src/tests/SharedScenarios/WhenAnyValue/SinglePropertyReactiveObject/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenAnyValue/SinglePropertyReactiveObject/MyViewModel.cs @@ -6,19 +6,13 @@ namespace SharedScenarios.WhenAnyValue.SinglePropertyReactiveObject; -/// -/// ViewModel extending ReactiveObject with a single string property. -/// +/// ViewModel extending ReactiveObject with a single string property. public class MyViewModel : ReactiveObject { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; diff --git a/src/tests/SharedScenarios/WhenAnyValue/SinglePropertyReactiveObject/Scenario.cs b/src/tests/SharedScenarios/WhenAnyValue/SinglePropertyReactiveObject/Scenario.cs index 91b92fa..a2e3b65 100644 --- a/src/tests/SharedScenarios/WhenAnyValue/SinglePropertyReactiveObject/Scenario.cs +++ b/src/tests/SharedScenarios/WhenAnyValue/SinglePropertyReactiveObject/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenAnyValue.SinglePropertyReactiveObject; -/// -/// Exercises WhenAnyValue on a ReactiveObject property. -/// +/// Exercises WhenAnyValue on a ReactiveObject property. public static class Scenario { - /// - /// Creates a WhenAnyValue observable for the Name property. - /// + /// Creates a WhenAnyValue observable for the Name property. /// The view model to observe. /// An observable of name values. - public static IObservable Execute(MyViewModel vm) - => vm.WhenAnyValue(x => x.Name); + public static IObservable Execute(MyViewModel vm) => + vm.WhenAnyValue(x => x.Name); } diff --git a/src/tests/SharedScenarios/WhenChanged/DeepPropertyChain/ChildModel.cs b/src/tests/SharedScenarios/WhenChanged/DeepPropertyChain/ChildModel.cs index 64463b1..e35e841 100644 --- a/src/tests/SharedScenarios/WhenChanged/DeepPropertyChain/ChildModel.cs +++ b/src/tests/SharedScenarios/WhenChanged/DeepPropertyChain/ChildModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.WhenChanged.DeepPropertyChain; -/// -/// Child model with a name property. -/// +/// Child model with a name property. public class ChildModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; diff --git a/src/tests/SharedScenarios/WhenChanged/DeepPropertyChain/ParentViewModel.cs b/src/tests/SharedScenarios/WhenChanged/DeepPropertyChain/ParentViewModel.cs index 9f89bc4..c492f8a 100644 --- a/src/tests/SharedScenarios/WhenChanged/DeepPropertyChain/ParentViewModel.cs +++ b/src/tests/SharedScenarios/WhenChanged/DeepPropertyChain/ParentViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.WhenChanged.DeepPropertyChain; -/// -/// Parent ViewModel containing a child model. -/// +/// Parent ViewModel containing a child model. public class ParentViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private ChildModel _child = new ChildModel(); /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the child model. - /// + /// Gets or sets the child model. public ChildModel Child { get => _child; diff --git a/src/tests/SharedScenarios/WhenChanged/DeepPropertyChain/Scenario.cs b/src/tests/SharedScenarios/WhenChanged/DeepPropertyChain/Scenario.cs index d6704ef..84c00f4 100644 --- a/src/tests/SharedScenarios/WhenChanged/DeepPropertyChain/Scenario.cs +++ b/src/tests/SharedScenarios/WhenChanged/DeepPropertyChain/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenChanged.DeepPropertyChain; -/// -/// Exercises WhenChanged with a deep property chain (x => x.Child.Name). -/// +/// Exercises WhenChanged with a deep property chain (x => x.Child.Name). public static class Scenario { - /// - /// Creates a WhenChanged observable for Child.Name. - /// + /// Creates a WhenChanged observable for Child.Name. /// The parent view model to observe. /// An observable of name values from the child. - public static IObservable Execute(ParentViewModel vm) - => vm.WhenChanged(x => x.Child.Name); + public static IObservable Execute(ParentViewModel vm) => + vm.WhenChanged(x => x.Child.Name); } diff --git a/src/tests/SharedScenarios/WhenChanged/FourLevelDeepChain/Level1.cs b/src/tests/SharedScenarios/WhenChanged/FourLevelDeepChain/Level1.cs index 73dd094..fe1b737 100644 --- a/src/tests/SharedScenarios/WhenChanged/FourLevelDeepChain/Level1.cs +++ b/src/tests/SharedScenarios/WhenChanged/FourLevelDeepChain/Level1.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.WhenChanged.FourLevelDeepChain; -/// -/// Top level in the deep chain. -/// +/// Top level in the deep chain. public class Level1 : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private Level2 _model = new Level2(); /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the level 2 model. - /// + /// Gets or sets the level 2 model. public Level2 Model { get => _model; diff --git a/src/tests/SharedScenarios/WhenChanged/FourLevelDeepChain/Level2.cs b/src/tests/SharedScenarios/WhenChanged/FourLevelDeepChain/Level2.cs index da92a2e..9f8a2c5 100644 --- a/src/tests/SharedScenarios/WhenChanged/FourLevelDeepChain/Level2.cs +++ b/src/tests/SharedScenarios/WhenChanged/FourLevelDeepChain/Level2.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.WhenChanged.FourLevelDeepChain; -/// -/// Second level in the deep chain. -/// +/// Second level in the deep chain. public class Level2 : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private Level3 _model = new Level3(); /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the level 3 model. - /// + /// Gets or sets the level 3 model. public Level3 Model { get => _model; diff --git a/src/tests/SharedScenarios/WhenChanged/FourLevelDeepChain/Level3.cs b/src/tests/SharedScenarios/WhenChanged/FourLevelDeepChain/Level3.cs index 900a388..c72f68b 100644 --- a/src/tests/SharedScenarios/WhenChanged/FourLevelDeepChain/Level3.cs +++ b/src/tests/SharedScenarios/WhenChanged/FourLevelDeepChain/Level3.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.WhenChanged.FourLevelDeepChain; -/// -/// Third level in the deep chain. -/// +/// Third level in the deep chain. public class Level3 : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private Model _model = new Model(); /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the model. - /// + /// Gets or sets the model. public Model Model { get => _model; diff --git a/src/tests/SharedScenarios/WhenChanged/FourLevelDeepChain/Model.cs b/src/tests/SharedScenarios/WhenChanged/FourLevelDeepChain/Model.cs index 8b2805d..05bdda4 100644 --- a/src/tests/SharedScenarios/WhenChanged/FourLevelDeepChain/Model.cs +++ b/src/tests/SharedScenarios/WhenChanged/FourLevelDeepChain/Model.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.WhenChanged.FourLevelDeepChain; -/// -/// Leaf model with a string value. -/// +/// Leaf model with a string value. public class Model : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _value = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the value. - /// + /// Gets or sets the value. public string Value { get => _value; diff --git a/src/tests/SharedScenarios/WhenChanged/FourLevelDeepChain/Scenario.cs b/src/tests/SharedScenarios/WhenChanged/FourLevelDeepChain/Scenario.cs index d36d212..327a759 100644 --- a/src/tests/SharedScenarios/WhenChanged/FourLevelDeepChain/Scenario.cs +++ b/src/tests/SharedScenarios/WhenChanged/FourLevelDeepChain/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenChanged.FourLevelDeepChain; -/// -/// Exercises WhenChanged with a 4-level deep property chain. -/// +/// Exercises WhenChanged with a 4-level deep property chain. public static class Scenario { - /// - /// Creates a WhenChanged observable for Model.Model.Model.Value. - /// + /// Creates a WhenChanged observable for Model.Model.Model.Value. /// The top-level object in the chain. /// An observable of value strings from the leaf. - public static IObservable Execute(Level1 chain) - => chain.WhenChanged(x => x.Model.Model.Model.Value); + public static IObservable Execute(Level1 chain) => + chain.WhenChanged(x => x.Model.Model.Model.Value); } diff --git a/src/tests/SharedScenarios/WhenChanged/IntProperty/MyViewModel.cs b/src/tests/SharedScenarios/WhenChanged/IntProperty/MyViewModel.cs index ecf8d55..17a615f 100644 --- a/src/tests/SharedScenarios/WhenChanged/IntProperty/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenChanged/IntProperty/MyViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.WhenChanged.IntProperty; -/// -/// ViewModel with an integer property. -/// +/// ViewModel with an integer property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private int _count; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the count. - /// + /// Gets or sets the count. public int Count { get => _count; diff --git a/src/tests/SharedScenarios/WhenChanged/IntProperty/Scenario.cs b/src/tests/SharedScenarios/WhenChanged/IntProperty/Scenario.cs index 63e67ba..3e083e0 100644 --- a/src/tests/SharedScenarios/WhenChanged/IntProperty/Scenario.cs +++ b/src/tests/SharedScenarios/WhenChanged/IntProperty/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenChanged.IntProperty; -/// -/// Exercises WhenChanged with an integer property type. -/// +/// Exercises WhenChanged with an integer property type. public static class Scenario { - /// - /// Creates a WhenChanged observable for the Count property. - /// + /// Creates a WhenChanged observable for the Count property. /// The view model to observe. /// An observable of count values. - public static IObservable Execute(MyViewModel vm) - => vm.WhenChanged(x => x.Count); + public static IObservable Execute(MyViewModel vm) => + vm.WhenChanged(x => x.Count); } diff --git a/src/tests/SharedScenarios/WhenChanged/MultiPropertyThreeProperties/MyViewModel.cs b/src/tests/SharedScenarios/WhenChanged/MultiPropertyThreeProperties/MyViewModel.cs index dc07caf..fafd06f 100644 --- a/src/tests/SharedScenarios/WhenChanged/MultiPropertyThreeProperties/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenChanged/MultiPropertyThreeProperties/MyViewModel.cs @@ -6,32 +6,22 @@ namespace SharedScenarios.WhenChanged.MultiPropertyThreeProperties; -/// -/// ViewModel with three observable properties. -/// +/// ViewModel with three observable properties. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private int _age; - /// - /// The backing field for . - /// + /// The backing field for . private double _score; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; @@ -47,9 +37,7 @@ public string Name } } - /// - /// Gets or sets the age. - /// + /// Gets or sets the age. public int Age { get => _age; @@ -65,9 +53,7 @@ public int Age } } - /// - /// Gets or sets the score. - /// + /// Gets or sets the score. public double Score { get => _score; diff --git a/src/tests/SharedScenarios/WhenChanged/MultiPropertyThreeProperties/Scenario.cs b/src/tests/SharedScenarios/WhenChanged/MultiPropertyThreeProperties/Scenario.cs index bf84feb..f65092a 100644 --- a/src/tests/SharedScenarios/WhenChanged/MultiPropertyThreeProperties/Scenario.cs +++ b/src/tests/SharedScenarios/WhenChanged/MultiPropertyThreeProperties/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenChanged.MultiPropertyThreeProperties; -/// -/// Exercises WhenChanged with three properties returning a tuple. -/// +/// Exercises WhenChanged with three properties returning a tuple. public static class Scenario { - /// - /// Creates a WhenChanged observable for Name, Age, and Score. - /// + /// Creates a WhenChanged observable for Name, Age, and Score. /// The view model to observe. /// An observable of (name, age, score) tuples. - public static IObservable<(string Name, int Age, double Score)> Execute(MyViewModel vm) - => vm.WhenChanged(x => x.Name, x => x.Age, x => x.Score); + public static IObservable<(string Name, int Age, double Score)> Execute(MyViewModel vm) => + vm.WhenChanged(x => x.Name, x => x.Age, x => x.Score); } diff --git a/src/tests/SharedScenarios/WhenChanged/MultiPropertyTwoProperties/MyViewModel.cs b/src/tests/SharedScenarios/WhenChanged/MultiPropertyTwoProperties/MyViewModel.cs index 6aff3c4..c62a19e 100644 --- a/src/tests/SharedScenarios/WhenChanged/MultiPropertyTwoProperties/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenChanged/MultiPropertyTwoProperties/MyViewModel.cs @@ -6,27 +6,19 @@ namespace SharedScenarios.WhenChanged.MultiPropertyTwoProperties; -/// -/// ViewModel with two observable properties. -/// +/// ViewModel with two observable properties. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private int _age; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; @@ -42,9 +34,7 @@ public string Name } } - /// - /// Gets or sets the age. - /// + /// Gets or sets the age. public int Age { get => _age; diff --git a/src/tests/SharedScenarios/WhenChanged/MultiPropertyTwoProperties/Scenario.cs b/src/tests/SharedScenarios/WhenChanged/MultiPropertyTwoProperties/Scenario.cs index 0d2b4d3..907487c 100644 --- a/src/tests/SharedScenarios/WhenChanged/MultiPropertyTwoProperties/Scenario.cs +++ b/src/tests/SharedScenarios/WhenChanged/MultiPropertyTwoProperties/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenChanged.MultiPropertyTwoProperties; -/// -/// Exercises WhenChanged with two properties returning a tuple. -/// +/// Exercises WhenChanged with two properties returning a tuple. public static class Scenario { - /// - /// Creates a WhenChanged observable for Name and Age. - /// + /// Creates a WhenChanged observable for Name and Age. /// The view model to observe. /// An observable of (name, age) tuples. - public static IObservable<(string Name, int Age)> Execute(MyViewModel vm) - => vm.WhenChanged(x => x.Name, x => x.Age); + public static IObservable<(string Name, int Age)> Execute(MyViewModel vm) => + vm.WhenChanged(x => x.Name, x => x.Age); } diff --git a/src/tests/SharedScenarios/WhenChanged/MultiPropertyWithDeepChains/AddressModel.cs b/src/tests/SharedScenarios/WhenChanged/MultiPropertyWithDeepChains/AddressModel.cs index cfd69da..fb22e61 100644 --- a/src/tests/SharedScenarios/WhenChanged/MultiPropertyWithDeepChains/AddressModel.cs +++ b/src/tests/SharedScenarios/WhenChanged/MultiPropertyWithDeepChains/AddressModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.WhenChanged.MultiPropertyWithDeepChains; -/// -/// Address model with a city property. -/// +/// Address model with a city property. public class AddressModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _city = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the city. - /// + /// Gets or sets the city. public string City { get => _city; diff --git a/src/tests/SharedScenarios/WhenChanged/MultiPropertyWithDeepChains/MyViewModel.cs b/src/tests/SharedScenarios/WhenChanged/MultiPropertyWithDeepChains/MyViewModel.cs index 3f796a4..1e6f227 100644 --- a/src/tests/SharedScenarios/WhenChanged/MultiPropertyWithDeepChains/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenChanged/MultiPropertyWithDeepChains/MyViewModel.cs @@ -6,27 +6,19 @@ namespace SharedScenarios.WhenChanged.MultiPropertyWithDeepChains; -/// -/// ViewModel with a shallow property and a deep property chain. -/// +/// ViewModel with a shallow property and a deep property chain. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private AddressModel _address = new AddressModel(); /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; @@ -42,9 +34,7 @@ public string Name } } - /// - /// Gets or sets the address. - /// + /// Gets or sets the address. public AddressModel Address { get => _address; diff --git a/src/tests/SharedScenarios/WhenChanged/MultiPropertyWithDeepChains/Scenario.cs b/src/tests/SharedScenarios/WhenChanged/MultiPropertyWithDeepChains/Scenario.cs index b26478f..c6aee8e 100644 --- a/src/tests/SharedScenarios/WhenChanged/MultiPropertyWithDeepChains/Scenario.cs +++ b/src/tests/SharedScenarios/WhenChanged/MultiPropertyWithDeepChains/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenChanged.MultiPropertyWithDeepChains; -/// -/// Exercises WhenChanged with a mix of deep chain (Address.City) and shallow (Name) properties. -/// +/// Exercises WhenChanged with a mix of deep chain (Address.City) and shallow (Name) properties. public static class Scenario { - /// - /// Creates a WhenChanged observable combining Address.City and Name with a selector. - /// + /// Creates a WhenChanged observable combining Address.City and Name with a selector. /// The view model to observe. /// An observable of combined city and name strings. - public static IObservable Execute(MyViewModel vm) - => vm.WhenChanged(x => x.Address.City, x => x.Name, (city, name) => $"{city}: {name}"); + public static IObservable Execute(MyViewModel vm) => + vm.WhenChanged(x => x.Address.City, x => x.Name, (city, name) => $"{city}: {name}"); } diff --git a/src/tests/SharedScenarios/WhenChanged/MultiPropertyWithSelector/MyViewModel.cs b/src/tests/SharedScenarios/WhenChanged/MultiPropertyWithSelector/MyViewModel.cs index 0ffdc3d..c8db75d 100644 --- a/src/tests/SharedScenarios/WhenChanged/MultiPropertyWithSelector/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenChanged/MultiPropertyWithSelector/MyViewModel.cs @@ -6,27 +6,19 @@ namespace SharedScenarios.WhenChanged.MultiPropertyWithSelector; -/// -/// ViewModel with first and last name properties. -/// +/// ViewModel with first and last name properties. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _firstName = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private string _lastName = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the first name. - /// + /// Gets or sets the first name. public string FirstName { get => _firstName; @@ -42,9 +34,7 @@ public string FirstName } } - /// - /// Gets or sets the last name. - /// + /// Gets or sets the last name. public string LastName { get => _lastName; diff --git a/src/tests/SharedScenarios/WhenChanged/MultiPropertyWithSelector/Scenario.cs b/src/tests/SharedScenarios/WhenChanged/MultiPropertyWithSelector/Scenario.cs index a3016f3..8df3cb4 100644 --- a/src/tests/SharedScenarios/WhenChanged/MultiPropertyWithSelector/Scenario.cs +++ b/src/tests/SharedScenarios/WhenChanged/MultiPropertyWithSelector/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenChanged.MultiPropertyWithSelector; -/// -/// Exercises WhenChanged with a selector function combining two properties. -/// +/// Exercises WhenChanged with a selector function combining two properties. public static class Scenario { - /// - /// Creates a WhenChanged observable combining FirstName and LastName. - /// + /// Creates a WhenChanged observable combining FirstName and LastName. /// The view model to observe. /// An observable of combined name strings. - public static IObservable Execute(MyViewModel vm) - => vm.WhenChanged(x => x.FirstName, x => x.LastName, (f, l) => $"{f} {l}"); + public static IObservable Execute(MyViewModel vm) => + vm.WhenChanged(x => x.FirstName, x => x.LastName, (f, l) => $"{f} {l}"); } diff --git a/src/tests/SharedScenarios/WhenChanged/MultipleInvocationsSameViewModel/MyViewModel.cs b/src/tests/SharedScenarios/WhenChanged/MultipleInvocationsSameViewModel/MyViewModel.cs index d9d4ff8..68b4379 100644 --- a/src/tests/SharedScenarios/WhenChanged/MultipleInvocationsSameViewModel/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenChanged/MultipleInvocationsSameViewModel/MyViewModel.cs @@ -6,32 +6,22 @@ namespace SharedScenarios.WhenChanged.MultipleInvocationsSameViewModel; -/// -/// ViewModel with multiple properties observed separately. -/// +/// ViewModel with multiple properties observed separately. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private int _age; - /// - /// The backing field for . - /// + /// The backing field for . private double _score; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; @@ -47,9 +37,7 @@ public string Name } } - /// - /// Gets or sets the age. - /// + /// Gets or sets the age. public int Age { get => _age; @@ -65,9 +53,7 @@ public int Age } } - /// - /// Gets or sets the score. - /// + /// Gets or sets the score. public double Score { get => _score; diff --git a/src/tests/SharedScenarios/WhenChanged/MultipleInvocationsSameViewModel/Scenario.cs b/src/tests/SharedScenarios/WhenChanged/MultipleInvocationsSameViewModel/Scenario.cs index d139487..ec4a303 100644 --- a/src/tests/SharedScenarios/WhenChanged/MultipleInvocationsSameViewModel/Scenario.cs +++ b/src/tests/SharedScenarios/WhenChanged/MultipleInvocationsSameViewModel/Scenario.cs @@ -7,17 +7,13 @@ namespace SharedScenarios.WhenChanged.MultipleInvocationsSameViewModel; -/// -/// Exercises multiple WhenChanged invocations on the same ViewModel. -/// +/// Exercises multiple WhenChanged invocations on the same ViewModel. public static class Scenario { - /// - /// Creates three separate WhenChanged observables for different properties. - /// + /// Creates three separate WhenChanged observables for different properties. /// The view model to observe. /// A tuple of observables for name, age, and score. public static (IObservable NameObs, IObservable AgeObs, IObservable ScoreObs) Execute( - MyViewModel vm) - => (vm.WhenChanged(x => x.Name), vm.WhenChanged(x => x.Age), vm.WhenChanged(x => x.Score)); + MyViewModel vm) => + (vm.WhenChanged(x => x.Name), vm.WhenChanged(x => x.Age), vm.WhenChanged(x => x.Score)); } diff --git a/src/tests/SharedScenarios/WhenChanged/MultipleViewModels/Scenario.cs b/src/tests/SharedScenarios/WhenChanged/MultipleViewModels/Scenario.cs index 017f624..dee5bc5 100644 --- a/src/tests/SharedScenarios/WhenChanged/MultipleViewModels/Scenario.cs +++ b/src/tests/SharedScenarios/WhenChanged/MultipleViewModels/Scenario.cs @@ -7,17 +7,13 @@ namespace SharedScenarios.WhenChanged.MultipleViewModels; -/// -/// Exercises WhenChanged with multiple ViewModels in the same compilation. -/// +/// Exercises WhenChanged with multiple ViewModels in the same compilation. public static class Scenario { - /// - /// Creates WhenChanged observables for two different ViewModels. - /// + /// Creates WhenChanged observables for two different ViewModels. /// The first view model. /// The second view model. /// A tuple of observables for name and count. - public static (IObservable NameObs, IObservable CountObs) Execute(ViewModel1 vm1, ViewModel2 vm2) - => (vm1.WhenChanged(x => x.Name), vm2.WhenChanged(x => x.Count)); + public static (IObservable NameObs, IObservable CountObs) Execute(ViewModel1 vm1, ViewModel2 vm2) => + (vm1.WhenChanged(x => x.Name), vm2.WhenChanged(x => x.Count)); } diff --git a/src/tests/SharedScenarios/WhenChanged/MultipleViewModels/ViewModel1.cs b/src/tests/SharedScenarios/WhenChanged/MultipleViewModels/ViewModel1.cs index 3ed2abe..7410891 100644 --- a/src/tests/SharedScenarios/WhenChanged/MultipleViewModels/ViewModel1.cs +++ b/src/tests/SharedScenarios/WhenChanged/MultipleViewModels/ViewModel1.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.WhenChanged.MultipleViewModels; -/// -/// First ViewModel with a name property. -/// +/// First ViewModel with a name property. public class ViewModel1 : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; diff --git a/src/tests/SharedScenarios/WhenChanged/MultipleViewModels/ViewModel2.cs b/src/tests/SharedScenarios/WhenChanged/MultipleViewModels/ViewModel2.cs index b418a53..9df6a73 100644 --- a/src/tests/SharedScenarios/WhenChanged/MultipleViewModels/ViewModel2.cs +++ b/src/tests/SharedScenarios/WhenChanged/MultipleViewModels/ViewModel2.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.WhenChanged.MultipleViewModels; -/// -/// Second ViewModel with a count property. -/// +/// Second ViewModel with a count property. public class ViewModel2 : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private int _count; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the count. - /// + /// Gets or sets the count. public int Count { get => _count; diff --git a/src/tests/SharedScenarios/WhenChanged/NullForgivingDeepChain/ChildModel.cs b/src/tests/SharedScenarios/WhenChanged/NullForgivingDeepChain/ChildModel.cs index be9796b..4c30e41 100644 --- a/src/tests/SharedScenarios/WhenChanged/NullForgivingDeepChain/ChildModel.cs +++ b/src/tests/SharedScenarios/WhenChanged/NullForgivingDeepChain/ChildModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.WhenChanged.NullForgivingDeepChain; -/// -/// Child model with a name property. -/// +/// Child model with a name property. public class ChildModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; diff --git a/src/tests/SharedScenarios/WhenChanged/NullForgivingDeepChain/ParentViewModel.cs b/src/tests/SharedScenarios/WhenChanged/NullForgivingDeepChain/ParentViewModel.cs index 8cef3b3..351bc56 100644 --- a/src/tests/SharedScenarios/WhenChanged/NullForgivingDeepChain/ParentViewModel.cs +++ b/src/tests/SharedScenarios/WhenChanged/NullForgivingDeepChain/ParentViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.WhenChanged.NullForgivingDeepChain; -/// -/// Parent ViewModel with a nullable child property. -/// +/// Parent ViewModel with a nullable child property. public class ParentViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private ChildModel? _child; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the nullable child model. - /// + /// Gets or sets the nullable child model. public ChildModel? Child { get => _child; diff --git a/src/tests/SharedScenarios/WhenChanged/NullForgivingDeepChain/Scenario.cs b/src/tests/SharedScenarios/WhenChanged/NullForgivingDeepChain/Scenario.cs index 7493102..e7a50aa 100644 --- a/src/tests/SharedScenarios/WhenChanged/NullForgivingDeepChain/Scenario.cs +++ b/src/tests/SharedScenarios/WhenChanged/NullForgivingDeepChain/Scenario.cs @@ -13,11 +13,9 @@ namespace SharedScenarios.WhenChanged.NullForgivingDeepChain; /// public static class Scenario { - /// - /// Creates a WhenChanged observable for Child!.Name using the null-forgiving operator. - /// + /// Creates a WhenChanged observable for Child!.Name using the null-forgiving operator. /// The parent view model to observe. /// An observable of name values from the child. - public static IObservable Execute(ParentViewModel vm) - => vm.WhenChanged(x => x.Child!.Name); + public static IObservable Execute(ParentViewModel vm) => + vm.WhenChanged(x => x.Child!.Name); } diff --git a/src/tests/SharedScenarios/WhenChanged/NullableProperty/MyViewModel.cs b/src/tests/SharedScenarios/WhenChanged/NullableProperty/MyViewModel.cs index a5da601..bf4a38e 100644 --- a/src/tests/SharedScenarios/WhenChanged/NullableProperty/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenChanged/NullableProperty/MyViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.WhenChanged.NullableProperty; -/// -/// ViewModel with a nullable string property. -/// +/// ViewModel with a nullable string property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string? _nullableName; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the nullable name. - /// + /// Gets or sets the nullable name. public string? NullableName { get => _nullableName; diff --git a/src/tests/SharedScenarios/WhenChanged/NullableProperty/Scenario.cs b/src/tests/SharedScenarios/WhenChanged/NullableProperty/Scenario.cs index 518721c..df2d8ca 100644 --- a/src/tests/SharedScenarios/WhenChanged/NullableProperty/Scenario.cs +++ b/src/tests/SharedScenarios/WhenChanged/NullableProperty/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenChanged.NullableProperty; -/// -/// Exercises WhenChanged with a nullable property type. -/// +/// Exercises WhenChanged with a nullable property type. public static class Scenario { - /// - /// Creates a WhenChanged observable for the NullableName property. - /// + /// Creates a WhenChanged observable for the NullableName property. /// The view model to observe. /// An observable of nullable name values. - public static IObservable Execute(MyViewModel vm) - => vm.WhenChanged(x => x.NullableName!); + public static IObservable Execute(MyViewModel vm) => + vm.WhenChanged(x => x.NullableName!); } diff --git a/src/tests/SharedScenarios/WhenChanged/SinglePropertyINPC/MyViewModel.cs b/src/tests/SharedScenarios/WhenChanged/SinglePropertyINPC/MyViewModel.cs index 37b4068..677c50d 100644 --- a/src/tests/SharedScenarios/WhenChanged/SinglePropertyINPC/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenChanged/SinglePropertyINPC/MyViewModel.cs @@ -6,22 +6,16 @@ namespace SharedScenarios.WhenChanged.SinglePropertyINPC; -/// -/// ViewModel implementing INotifyPropertyChanged with a single string property. -/// +/// ViewModel implementing INotifyPropertyChanged with a single string property. public class MyViewModel : INotifyPropertyChanged { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; /// public event PropertyChangedEventHandler? PropertyChanged; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; diff --git a/src/tests/SharedScenarios/WhenChanged/SinglePropertyINPC/Scenario.cs b/src/tests/SharedScenarios/WhenChanged/SinglePropertyINPC/Scenario.cs index b57a61c..1ce3069 100644 --- a/src/tests/SharedScenarios/WhenChanged/SinglePropertyINPC/Scenario.cs +++ b/src/tests/SharedScenarios/WhenChanged/SinglePropertyINPC/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenChanged.SinglePropertyINPC; -/// -/// Exercises WhenChanged on a single INPC property. -/// +/// Exercises WhenChanged on a single INPC property. public static class Scenario { - /// - /// Creates a WhenChanged observable for the Name property. - /// + /// Creates a WhenChanged observable for the Name property. /// The view model to observe. /// An observable of name values. - public static IObservable Execute(MyViewModel vm) - => vm.WhenChanged(x => x.Name); + public static IObservable Execute(MyViewModel vm) => + vm.WhenChanged(x => x.Name); } diff --git a/src/tests/SharedScenarios/WhenChanged/SinglePropertyReactiveObject/MyViewModel.cs b/src/tests/SharedScenarios/WhenChanged/SinglePropertyReactiveObject/MyViewModel.cs index 3307c03..e82ff69 100644 --- a/src/tests/SharedScenarios/WhenChanged/SinglePropertyReactiveObject/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenChanged/SinglePropertyReactiveObject/MyViewModel.cs @@ -6,19 +6,13 @@ namespace SharedScenarios.WhenChanged.SinglePropertyReactiveObject; -/// -/// ViewModel extending ReactiveObject with a single string property. -/// +/// ViewModel extending ReactiveObject with a single string property. public class MyViewModel : ReactiveObject { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; diff --git a/src/tests/SharedScenarios/WhenChanged/SinglePropertyReactiveObject/Scenario.cs b/src/tests/SharedScenarios/WhenChanged/SinglePropertyReactiveObject/Scenario.cs index 6a14898..f289298 100644 --- a/src/tests/SharedScenarios/WhenChanged/SinglePropertyReactiveObject/Scenario.cs +++ b/src/tests/SharedScenarios/WhenChanged/SinglePropertyReactiveObject/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenChanged.SinglePropertyReactiveObject; -/// -/// Exercises WhenChanged on a ReactiveObject property. -/// +/// Exercises WhenChanged on a ReactiveObject property. public static class Scenario { - /// - /// Creates a WhenChanged observable for the Name property. - /// + /// Creates a WhenChanged observable for the Name property. /// The view model to observe. /// An observable of name values. - public static IObservable Execute(MyViewModel vm) - => vm.WhenChanged(x => x.Name); + public static IObservable Execute(MyViewModel vm) => + vm.WhenChanged(x => x.Name); } diff --git a/src/tests/SharedScenarios/WhenChanging/DeepPropertyChain/ChildModel.cs b/src/tests/SharedScenarios/WhenChanging/DeepPropertyChain/ChildModel.cs index ff64d3d..f7ce731 100644 --- a/src/tests/SharedScenarios/WhenChanging/DeepPropertyChain/ChildModel.cs +++ b/src/tests/SharedScenarios/WhenChanging/DeepPropertyChain/ChildModel.cs @@ -6,14 +6,10 @@ namespace SharedScenarios.WhenChanging.DeepPropertyChain; -/// -/// Child model with before-change notifications. -/// +/// Child model with before-change notifications. public class ChildModel : INotifyPropertyChanged, INotifyPropertyChanging { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; /// @@ -22,9 +18,7 @@ public class ChildModel : INotifyPropertyChanged, INotifyPropertyChanging /// public event PropertyChangingEventHandler? PropertyChanging; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; diff --git a/src/tests/SharedScenarios/WhenChanging/DeepPropertyChain/ParentViewModel.cs b/src/tests/SharedScenarios/WhenChanging/DeepPropertyChain/ParentViewModel.cs index d20089f..c45262e 100644 --- a/src/tests/SharedScenarios/WhenChanging/DeepPropertyChain/ParentViewModel.cs +++ b/src/tests/SharedScenarios/WhenChanging/DeepPropertyChain/ParentViewModel.cs @@ -6,14 +6,10 @@ namespace SharedScenarios.WhenChanging.DeepPropertyChain; -/// -/// Parent ViewModel with before-change notifications. -/// +/// Parent ViewModel with before-change notifications. public class ParentViewModel : INotifyPropertyChanged, INotifyPropertyChanging { - /// - /// The backing field for . - /// + /// The backing field for . private ChildModel _child = new ChildModel(); /// @@ -22,9 +18,7 @@ public class ParentViewModel : INotifyPropertyChanged, INotifyPropertyChanging /// public event PropertyChangingEventHandler? PropertyChanging; - /// - /// Gets or sets the child model. - /// + /// Gets or sets the child model. public ChildModel Child { get => _child; diff --git a/src/tests/SharedScenarios/WhenChanging/DeepPropertyChain/Scenario.cs b/src/tests/SharedScenarios/WhenChanging/DeepPropertyChain/Scenario.cs index d20d3c0..74e0a91 100644 --- a/src/tests/SharedScenarios/WhenChanging/DeepPropertyChain/Scenario.cs +++ b/src/tests/SharedScenarios/WhenChanging/DeepPropertyChain/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenChanging.DeepPropertyChain; -/// -/// Exercises WhenChanging with a deep property chain. -/// +/// Exercises WhenChanging with a deep property chain. public static class Scenario { - /// - /// Creates a WhenChanging observable for Child.Name. - /// + /// Creates a WhenChanging observable for Child.Name. /// The parent view model to observe. /// An observable of name values (before change). - public static IObservable Execute(ParentViewModel vm) - => vm.WhenChanging(x => x.Child.Name); + public static IObservable Execute(ParentViewModel vm) => + vm.WhenChanging(x => x.Child.Name); } diff --git a/src/tests/SharedScenarios/WhenChanging/FourLevelDeepChain/Level1.cs b/src/tests/SharedScenarios/WhenChanging/FourLevelDeepChain/Level1.cs index cf3a1ea..81613d6 100644 --- a/src/tests/SharedScenarios/WhenChanging/FourLevelDeepChain/Level1.cs +++ b/src/tests/SharedScenarios/WhenChanging/FourLevelDeepChain/Level1.cs @@ -6,14 +6,10 @@ namespace SharedScenarios.WhenChanging.FourLevelDeepChain; -/// -/// Top level in the deep chain with before-change notifications. -/// +/// Top level in the deep chain with before-change notifications. public class Level1 : INotifyPropertyChanged, INotifyPropertyChanging { - /// - /// The backing field for . - /// + /// The backing field for . private Level2 _model = new Level2(); /// @@ -22,9 +18,7 @@ public class Level1 : INotifyPropertyChanged, INotifyPropertyChanging /// public event PropertyChangingEventHandler? PropertyChanging; - /// - /// Gets or sets the level 2 model. - /// + /// Gets or sets the level 2 model. public Level2 Model { get => _model; diff --git a/src/tests/SharedScenarios/WhenChanging/FourLevelDeepChain/Level2.cs b/src/tests/SharedScenarios/WhenChanging/FourLevelDeepChain/Level2.cs index 9b04364..4fd477e 100644 --- a/src/tests/SharedScenarios/WhenChanging/FourLevelDeepChain/Level2.cs +++ b/src/tests/SharedScenarios/WhenChanging/FourLevelDeepChain/Level2.cs @@ -6,14 +6,10 @@ namespace SharedScenarios.WhenChanging.FourLevelDeepChain; -/// -/// Second level in the deep chain with before-change notifications. -/// +/// Second level in the deep chain with before-change notifications. public class Level2 : INotifyPropertyChanged, INotifyPropertyChanging { - /// - /// The backing field for . - /// + /// The backing field for . private Level3 _model = new Level3(); /// @@ -22,9 +18,7 @@ public class Level2 : INotifyPropertyChanged, INotifyPropertyChanging /// public event PropertyChangingEventHandler? PropertyChanging; - /// - /// Gets or sets the level 3 model. - /// + /// Gets or sets the level 3 model. public Level3 Model { get => _model; diff --git a/src/tests/SharedScenarios/WhenChanging/FourLevelDeepChain/Level3.cs b/src/tests/SharedScenarios/WhenChanging/FourLevelDeepChain/Level3.cs index 39c890e..5753155 100644 --- a/src/tests/SharedScenarios/WhenChanging/FourLevelDeepChain/Level3.cs +++ b/src/tests/SharedScenarios/WhenChanging/FourLevelDeepChain/Level3.cs @@ -6,14 +6,10 @@ namespace SharedScenarios.WhenChanging.FourLevelDeepChain; -/// -/// Third level in the deep chain with before-change notifications. -/// +/// Third level in the deep chain with before-change notifications. public class Level3 : INotifyPropertyChanged, INotifyPropertyChanging { - /// - /// The backing field for . - /// + /// The backing field for . private Model _model = new Model(); /// @@ -22,9 +18,7 @@ public class Level3 : INotifyPropertyChanged, INotifyPropertyChanging /// public event PropertyChangingEventHandler? PropertyChanging; - /// - /// Gets or sets the model. - /// + /// Gets or sets the model. public Model Model { get => _model; diff --git a/src/tests/SharedScenarios/WhenChanging/FourLevelDeepChain/Model.cs b/src/tests/SharedScenarios/WhenChanging/FourLevelDeepChain/Model.cs index cfdc7c6..e53e3fe 100644 --- a/src/tests/SharedScenarios/WhenChanging/FourLevelDeepChain/Model.cs +++ b/src/tests/SharedScenarios/WhenChanging/FourLevelDeepChain/Model.cs @@ -6,14 +6,10 @@ namespace SharedScenarios.WhenChanging.FourLevelDeepChain; -/// -/// Leaf model with a string value and before-change notifications. -/// +/// Leaf model with a string value and before-change notifications. public class Model : INotifyPropertyChanged, INotifyPropertyChanging { - /// - /// The backing field for . - /// + /// The backing field for . private string _value = string.Empty; /// @@ -22,9 +18,7 @@ public class Model : INotifyPropertyChanged, INotifyPropertyChanging /// public event PropertyChangingEventHandler? PropertyChanging; - /// - /// Gets or sets the value. - /// + /// Gets or sets the value. public string Value { get => _value; diff --git a/src/tests/SharedScenarios/WhenChanging/FourLevelDeepChain/Scenario.cs b/src/tests/SharedScenarios/WhenChanging/FourLevelDeepChain/Scenario.cs index 2e619ec..ad64c06 100644 --- a/src/tests/SharedScenarios/WhenChanging/FourLevelDeepChain/Scenario.cs +++ b/src/tests/SharedScenarios/WhenChanging/FourLevelDeepChain/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenChanging.FourLevelDeepChain; -/// -/// Exercises WhenChanging with a 4-level deep property chain. -/// +/// Exercises WhenChanging with a 4-level deep property chain. public static class Scenario { - /// - /// Creates a WhenChanging observable for Model.Model.Model.Value. - /// + /// Creates a WhenChanging observable for Model.Model.Model.Value. /// The top-level object in the chain. /// An observable of value strings from the leaf (before change). - public static IObservable Execute(Level1 chain) - => chain.WhenChanging(x => x.Model.Model.Model.Value); + public static IObservable Execute(Level1 chain) => + chain.WhenChanging(x => x.Model.Model.Model.Value); } diff --git a/src/tests/SharedScenarios/WhenChanging/MultiPropertyThreeProperties/MyViewModel.cs b/src/tests/SharedScenarios/WhenChanging/MultiPropertyThreeProperties/MyViewModel.cs index 36ccb8f..5c632ef 100644 --- a/src/tests/SharedScenarios/WhenChanging/MultiPropertyThreeProperties/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenChanging/MultiPropertyThreeProperties/MyViewModel.cs @@ -6,24 +6,16 @@ namespace SharedScenarios.WhenChanging.MultiPropertyThreeProperties; -/// -/// ViewModel with three observable properties supporting before-change notifications. -/// +/// ViewModel with three observable properties supporting before-change notifications. public class MyViewModel : INotifyPropertyChanged, INotifyPropertyChanging { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private int _age; - /// - /// The backing field for . - /// + /// The backing field for . private double _score; /// @@ -32,9 +24,7 @@ public class MyViewModel : INotifyPropertyChanged, INotifyPropertyChanging /// public event PropertyChangingEventHandler? PropertyChanging; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; @@ -51,9 +41,7 @@ public string Name } } - /// - /// Gets or sets the age. - /// + /// Gets or sets the age. public int Age { get => _age; @@ -70,9 +58,7 @@ public int Age } } - /// - /// Gets or sets the score. - /// + /// Gets or sets the score. public double Score { get => _score; diff --git a/src/tests/SharedScenarios/WhenChanging/MultiPropertyThreeProperties/Scenario.cs b/src/tests/SharedScenarios/WhenChanging/MultiPropertyThreeProperties/Scenario.cs index 6b82092..0006287 100644 --- a/src/tests/SharedScenarios/WhenChanging/MultiPropertyThreeProperties/Scenario.cs +++ b/src/tests/SharedScenarios/WhenChanging/MultiPropertyThreeProperties/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenChanging.MultiPropertyThreeProperties; -/// -/// Exercises WhenChanging with three properties returning a tuple. -/// +/// Exercises WhenChanging with three properties returning a tuple. public static class Scenario { - /// - /// Creates a WhenChanging observable for Name, Age, and Score. - /// + /// Creates a WhenChanging observable for Name, Age, and Score. /// The view model to observe. /// An observable of (name, age, score) tuples (before change). - public static IObservable<(string Name, int Age, double Score)> Execute(MyViewModel vm) - => vm.WhenChanging(x => x.Name, x => x.Age, x => x.Score); + public static IObservable<(string Name, int Age, double Score)> Execute(MyViewModel vm) => + vm.WhenChanging(x => x.Name, x => x.Age, x => x.Score); } diff --git a/src/tests/SharedScenarios/WhenChanging/MultiPropertyTwoProperties/MyViewModel.cs b/src/tests/SharedScenarios/WhenChanging/MultiPropertyTwoProperties/MyViewModel.cs index 6aa31ee..f74cdc2 100644 --- a/src/tests/SharedScenarios/WhenChanging/MultiPropertyTwoProperties/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenChanging/MultiPropertyTwoProperties/MyViewModel.cs @@ -6,19 +6,13 @@ namespace SharedScenarios.WhenChanging.MultiPropertyTwoProperties; -/// -/// ViewModel with two observable properties supporting before-change notifications. -/// +/// ViewModel with two observable properties supporting before-change notifications. public class MyViewModel : INotifyPropertyChanged, INotifyPropertyChanging { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private int _age; /// @@ -27,9 +21,7 @@ public class MyViewModel : INotifyPropertyChanged, INotifyPropertyChanging /// public event PropertyChangingEventHandler? PropertyChanging; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; @@ -46,9 +38,7 @@ public string Name } } - /// - /// Gets or sets the age. - /// + /// Gets or sets the age. public int Age { get => _age; diff --git a/src/tests/SharedScenarios/WhenChanging/MultiPropertyTwoProperties/Scenario.cs b/src/tests/SharedScenarios/WhenChanging/MultiPropertyTwoProperties/Scenario.cs index 0025b43..5ca07a8 100644 --- a/src/tests/SharedScenarios/WhenChanging/MultiPropertyTwoProperties/Scenario.cs +++ b/src/tests/SharedScenarios/WhenChanging/MultiPropertyTwoProperties/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenChanging.MultiPropertyTwoProperties; -/// -/// Exercises WhenChanging with two properties returning a tuple. -/// +/// Exercises WhenChanging with two properties returning a tuple. public static class Scenario { - /// - /// Creates a WhenChanging observable for Name and Age. - /// + /// Creates a WhenChanging observable for Name and Age. /// The view model to observe. /// An observable of (name, age) tuples (before change). - public static IObservable<(string Name, int Age)> Execute(MyViewModel vm) - => vm.WhenChanging(x => x.Name, x => x.Age); + public static IObservable<(string Name, int Age)> Execute(MyViewModel vm) => + vm.WhenChanging(x => x.Name, x => x.Age); } diff --git a/src/tests/SharedScenarios/WhenChanging/MultiPropertyWithDeepChains/AddressModel.cs b/src/tests/SharedScenarios/WhenChanging/MultiPropertyWithDeepChains/AddressModel.cs index 118837e..9bdc049 100644 --- a/src/tests/SharedScenarios/WhenChanging/MultiPropertyWithDeepChains/AddressModel.cs +++ b/src/tests/SharedScenarios/WhenChanging/MultiPropertyWithDeepChains/AddressModel.cs @@ -6,14 +6,10 @@ namespace SharedScenarios.WhenChanging.MultiPropertyWithDeepChains; -/// -/// Address model with a city property and before-change notifications. -/// +/// Address model with a city property and before-change notifications. public class AddressModel : INotifyPropertyChanged, INotifyPropertyChanging { - /// - /// The backing field for . - /// + /// The backing field for . private string _city = string.Empty; /// @@ -22,9 +18,7 @@ public class AddressModel : INotifyPropertyChanged, INotifyPropertyChanging /// public event PropertyChangingEventHandler? PropertyChanging; - /// - /// Gets or sets the city. - /// + /// Gets or sets the city. public string City { get => _city; diff --git a/src/tests/SharedScenarios/WhenChanging/MultiPropertyWithDeepChains/MyViewModel.cs b/src/tests/SharedScenarios/WhenChanging/MultiPropertyWithDeepChains/MyViewModel.cs index 0a57898..1dab39a 100644 --- a/src/tests/SharedScenarios/WhenChanging/MultiPropertyWithDeepChains/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenChanging/MultiPropertyWithDeepChains/MyViewModel.cs @@ -6,19 +6,13 @@ namespace SharedScenarios.WhenChanging.MultiPropertyWithDeepChains; -/// -/// ViewModel with a shallow property and a deep property chain, supporting before-change notifications. -/// +/// ViewModel with a shallow property and a deep property chain, supporting before-change notifications. public class MyViewModel : INotifyPropertyChanged, INotifyPropertyChanging { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private AddressModel _address = new AddressModel(); /// @@ -27,9 +21,7 @@ public class MyViewModel : INotifyPropertyChanged, INotifyPropertyChanging /// public event PropertyChangingEventHandler? PropertyChanging; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; @@ -46,9 +38,7 @@ public string Name } } - /// - /// Gets or sets the address. - /// + /// Gets or sets the address. public AddressModel Address { get => _address; diff --git a/src/tests/SharedScenarios/WhenChanging/MultiPropertyWithDeepChains/Scenario.cs b/src/tests/SharedScenarios/WhenChanging/MultiPropertyWithDeepChains/Scenario.cs index 35cada1..f097561 100644 --- a/src/tests/SharedScenarios/WhenChanging/MultiPropertyWithDeepChains/Scenario.cs +++ b/src/tests/SharedScenarios/WhenChanging/MultiPropertyWithDeepChains/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenChanging.MultiPropertyWithDeepChains; -/// -/// Exercises WhenChanging with a mix of deep chain (Address.City) and shallow (Name) properties. -/// +/// Exercises WhenChanging with a mix of deep chain (Address.City) and shallow (Name) properties. public static class Scenario { - /// - /// Creates a WhenChanging observable combining Address.City and Name with a selector. - /// + /// Creates a WhenChanging observable combining Address.City and Name with a selector. /// The view model to observe. /// An observable of combined city and name strings (before change). - public static IObservable Execute(MyViewModel vm) - => vm.WhenChanging(x => x.Address.City, x => x.Name, (city, name) => $"{city}: {name}"); + public static IObservable Execute(MyViewModel vm) => + vm.WhenChanging(x => x.Address.City, x => x.Name, (city, name) => $"{city}: {name}"); } diff --git a/src/tests/SharedScenarios/WhenChanging/MultiPropertyWithSelector/MyViewModel.cs b/src/tests/SharedScenarios/WhenChanging/MultiPropertyWithSelector/MyViewModel.cs index a553aec..c70a597 100644 --- a/src/tests/SharedScenarios/WhenChanging/MultiPropertyWithSelector/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenChanging/MultiPropertyWithSelector/MyViewModel.cs @@ -6,19 +6,13 @@ namespace SharedScenarios.WhenChanging.MultiPropertyWithSelector; -/// -/// ViewModel with first and last name, supporting before-change notifications. -/// +/// ViewModel with first and last name, supporting before-change notifications. public class MyViewModel : INotifyPropertyChanged, INotifyPropertyChanging { - /// - /// The backing field for . - /// + /// The backing field for . private string _firstName = string.Empty; - /// - /// The backing field for . - /// + /// The backing field for . private string _lastName = string.Empty; /// @@ -27,9 +21,7 @@ public class MyViewModel : INotifyPropertyChanged, INotifyPropertyChanging /// public event PropertyChangingEventHandler? PropertyChanging; - /// - /// Gets or sets the first name. - /// + /// Gets or sets the first name. public string FirstName { get => _firstName; @@ -46,9 +38,7 @@ public string FirstName } } - /// - /// Gets or sets the last name. - /// + /// Gets or sets the last name. public string LastName { get => _lastName; diff --git a/src/tests/SharedScenarios/WhenChanging/MultiPropertyWithSelector/Scenario.cs b/src/tests/SharedScenarios/WhenChanging/MultiPropertyWithSelector/Scenario.cs index 4a23eb6..f885321 100644 --- a/src/tests/SharedScenarios/WhenChanging/MultiPropertyWithSelector/Scenario.cs +++ b/src/tests/SharedScenarios/WhenChanging/MultiPropertyWithSelector/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenChanging.MultiPropertyWithSelector; -/// -/// Exercises WhenChanging with a selector function combining two properties. -/// +/// Exercises WhenChanging with a selector function combining two properties. public static class Scenario { - /// - /// Creates a WhenChanging observable combining FirstName and LastName. - /// + /// Creates a WhenChanging observable combining FirstName and LastName. /// The view model to observe. /// An observable of combined name strings (before change). - public static IObservable Execute(MyViewModel vm) - => vm.WhenChanging(x => x.FirstName, x => x.LastName, (f, l) => $"{f} {l}"); + public static IObservable Execute(MyViewModel vm) => + vm.WhenChanging(x => x.FirstName, x => x.LastName, (f, l) => $"{f} {l}"); } diff --git a/src/tests/SharedScenarios/WhenChanging/SinglePropertyINPC/MyViewModel.cs b/src/tests/SharedScenarios/WhenChanging/SinglePropertyINPC/MyViewModel.cs index c9ea548..2700c16 100644 --- a/src/tests/SharedScenarios/WhenChanging/SinglePropertyINPC/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenChanging/SinglePropertyINPC/MyViewModel.cs @@ -6,14 +6,10 @@ namespace SharedScenarios.WhenChanging.SinglePropertyINPC; -/// -/// ViewModel implementing both INPC and INotifyPropertyChanging. -/// +/// ViewModel implementing both INPC and INotifyPropertyChanging. public class MyViewModel : INotifyPropertyChanged, INotifyPropertyChanging { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; /// @@ -22,9 +18,7 @@ public class MyViewModel : INotifyPropertyChanged, INotifyPropertyChanging /// public event PropertyChangingEventHandler? PropertyChanging; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; diff --git a/src/tests/SharedScenarios/WhenChanging/SinglePropertyINPC/Scenario.cs b/src/tests/SharedScenarios/WhenChanging/SinglePropertyINPC/Scenario.cs index b93b428..d464f55 100644 --- a/src/tests/SharedScenarios/WhenChanging/SinglePropertyINPC/Scenario.cs +++ b/src/tests/SharedScenarios/WhenChanging/SinglePropertyINPC/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenChanging.SinglePropertyINPC; -/// -/// Exercises WhenChanging on a single INPC property. -/// +/// Exercises WhenChanging on a single INPC property. public static class Scenario { - /// - /// Creates a WhenChanging observable for the Name property. - /// + /// Creates a WhenChanging observable for the Name property. /// The view model to observe. /// An observable of name values (before change). - public static IObservable Execute(MyViewModel vm) - => vm.WhenChanging(x => x.Name); + public static IObservable Execute(MyViewModel vm) => + vm.WhenChanging(x => x.Name); } diff --git a/src/tests/SharedScenarios/WhenChanging/SinglePropertyReactiveObject/MyViewModel.cs b/src/tests/SharedScenarios/WhenChanging/SinglePropertyReactiveObject/MyViewModel.cs index fb77390..a36fa96 100644 --- a/src/tests/SharedScenarios/WhenChanging/SinglePropertyReactiveObject/MyViewModel.cs +++ b/src/tests/SharedScenarios/WhenChanging/SinglePropertyReactiveObject/MyViewModel.cs @@ -6,19 +6,13 @@ namespace SharedScenarios.WhenChanging.SinglePropertyReactiveObject; -/// -/// ViewModel extending ReactiveObject (which implements both INPC and INPChanging). -/// +/// ViewModel extending ReactiveObject (which implements both INPC and INPChanging). public class MyViewModel : ReactiveObject { - /// - /// The backing field for . - /// + /// The backing field for . private string _name = string.Empty; - /// - /// Gets or sets the name. - /// + /// Gets or sets the name. public string Name { get => _name; diff --git a/src/tests/SharedScenarios/WhenChanging/SinglePropertyReactiveObject/Scenario.cs b/src/tests/SharedScenarios/WhenChanging/SinglePropertyReactiveObject/Scenario.cs index 6ce0f0f..9f03adf 100644 --- a/src/tests/SharedScenarios/WhenChanging/SinglePropertyReactiveObject/Scenario.cs +++ b/src/tests/SharedScenarios/WhenChanging/SinglePropertyReactiveObject/Scenario.cs @@ -7,16 +7,12 @@ namespace SharedScenarios.WhenChanging.SinglePropertyReactiveObject; -/// -/// Exercises WhenChanging on a ReactiveObject property. -/// +/// Exercises WhenChanging on a ReactiveObject property. public static class Scenario { - /// - /// Creates a WhenChanging observable for the Name property. - /// + /// Creates a WhenChanging observable for the Name property. /// The view model to observe. /// An observable of name values (before change). - public static IObservable Execute(MyViewModel vm) - => vm.WhenChanging(x => x.Name); + public static IObservable Execute(MyViewModel vm) => + vm.WhenChanging(x => x.Name); }