1+ using System . Runtime . CompilerServices ;
2+ using System . Runtime . InteropServices ;
3+
4+ namespace DotNext . Runtime ;
5+
6+ [ TestClass ]
7+ public class ValueReferenceTests
8+ {
9+ [ TestMethod ]
10+ public void MutableFieldRef ( )
11+ {
12+ var obj = new MyClass { AnotherField = string . Empty } ;
13+ var reference = new ValueReference < int > ( obj , ref obj . Field ) ;
14+
15+ obj . Field = 20 ;
16+ Assert . AreEqual ( obj . Field , reference . Value ) ;
17+
18+ reference . Value = 42 ;
19+ Assert . AreEqual ( obj . Field , reference . Value ) ;
20+ Assert . IsTrue ( string . IsNullOrEmpty ( obj . AnotherField ) ) ;
21+ }
22+
23+ [ TestMethod ]
24+ public void ImmutableFieldRef ( )
25+ {
26+ var obj = new MyClass { AnotherField = string . Empty } ;
27+ var reference = new ReadOnlyValueReference < int > ( obj , in obj . Field ) ;
28+
29+ obj . Field = 20 ;
30+ Assert . AreEqual ( obj . Field , reference . Value ) ;
31+
32+ Assert . AreEqual ( obj . Field , reference . Value ) ;
33+ Assert . IsTrue ( string . IsNullOrEmpty ( obj . AnotherField ) ) ;
34+ }
35+
36+ [ TestMethod ]
37+ public void MutableToImmutableRef ( )
38+ {
39+ var obj = new MyClass { AnotherField = string . Empty } ;
40+ var reference = new ValueReference < int > ( obj , ref obj . Field ) ;
41+ ReadOnlyValueReference < int > roReference = reference ;
42+
43+ obj . Field = 20 ;
44+ Assert . AreEqual ( roReference . Value , reference . Value ) ;
45+
46+ reference . Value = 42 ;
47+ Assert . AreEqual ( roReference . Value , reference . Value ) ;
48+ }
49+
50+ [ TestMethod ]
51+ public void MutableRefEquality ( )
52+ {
53+ var obj = new MyClass { AnotherField = string . Empty } ;
54+ var reference1 = new ValueReference < int > ( obj , ref obj . Field ) ;
55+ var reference2 = new ValueReference < int > ( obj , ref obj . Field ) ;
56+
57+ Assert . AreEqual ( reference1 , reference2 ) ;
58+ }
59+
60+ [ TestMethod ]
61+ public void ImmutableRefEquality ( )
62+ {
63+ var obj = new MyClass { AnotherField = string . Empty } ;
64+ var reference1 = new ReadOnlyValueReference < int > ( obj , in obj . Field ) ;
65+ var reference2 = new ReadOnlyValueReference < int > ( obj , in obj . Field ) ;
66+
67+ Assert . AreEqual ( reference1 , reference2 ) ;
68+ }
69+
70+ [ TestMethod ]
71+ public void ReferenceToArray ( )
72+ {
73+ var array = new string [ 1 ] ;
74+ var reference = new ValueReference < string > ( array , 0 )
75+ {
76+ Value = "Hello, world!"
77+ } ;
78+
79+ Assert . AreSame ( array [ 0 ] , reference . Value ) ;
80+ Assert . AreSame ( array [ 0 ] , reference . ToString ( ) ) ;
81+ }
82+
83+ [ TestMethod ]
84+ public void MutableEmptyRef ( )
85+ {
86+ var reference = default ( ValueReference < string > ) ;
87+ Assert . IsTrue ( reference . IsEmpty ) ;
88+ Assert . IsNull ( reference . ToString ( ) ) ;
89+
90+ Span < string > span = reference ;
91+ Assert . IsTrue ( span . IsEmpty ) ;
92+
93+ Assert . ThrowsException < NullReferenceException > ( ( Func < string > ) reference ) ;
94+ Assert . ThrowsException < NullReferenceException > ( ( ( Action < string > ) reference ) . Bind ( string . Empty ) ) ;
95+ }
96+
97+ [ TestMethod ]
98+ public void ImmutableEmptyRef ( )
99+ {
100+ var reference = default ( ReadOnlyValueReference < string > ) ;
101+ Assert . IsTrue ( reference . IsEmpty ) ;
102+ Assert . IsNull ( reference . ToString ( ) ) ;
103+
104+ ReadOnlySpan < string > span = reference ;
105+ Assert . IsTrue ( span . IsEmpty ) ;
106+
107+ Assert . ThrowsException < NullReferenceException > ( ( Func < string > ) reference ) ;
108+ }
109+
110+ [ TestMethod ]
111+ public void AnonymousValue ( )
112+ {
113+ var reference = new ValueReference < int > ( 42 ) ;
114+ Assert . AreEqual ( 42 , reference . Value ) ;
115+
116+ ( ( Action < int > ) reference ) . Invoke ( 52 ) ;
117+ Assert . AreEqual ( 52 , ToFunc < ValueReference < int > , int > ( reference ) . Invoke ( ) ) ;
118+
119+ ReadOnlyValueReference < int > roRef = reference ;
120+ Assert . AreEqual ( 52 , roRef . Value ) ;
121+ Assert . AreEqual ( 52 , ToFunc < ReadOnlyValueReference < int > , int > ( reference ) . Invoke ( ) ) ;
122+ }
123+
124+ private static Func < T > ToFunc < TSupplier , T > ( TSupplier supplier )
125+ where TSupplier : ISupplier < T >
126+ => supplier . ToDelegate ( ) ;
127+
128+ [ TestMethod ]
129+ public void IncorrectReference ( )
130+ {
131+ byte [ ] empty = [ ] ;
132+ Assert . ThrowsException < ArgumentOutOfRangeException > ( ( ) => new ValueReference < byte > ( empty , ref MemoryMarshal . GetArrayDataReference ( empty ) ) ) ;
133+ Assert . ThrowsException < ArgumentOutOfRangeException > ( ( ) => new ReadOnlyValueReference < byte > ( empty , ref MemoryMarshal . GetArrayDataReference ( empty ) ) ) ;
134+ }
135+
136+ [ TestMethod ]
137+ public void ReferenceSize ( )
138+ {
139+ Assert . AreEqual ( Unsafe . SizeOf < ValueReference < float > > ( ) , nint . Size + nint . Size ) ;
140+ }
141+
142+ [ TestMethod ]
143+ public void BoxedValueInterop ( )
144+ {
145+ var boxedInt = BoxedValue < int > . Box ( 42 ) ;
146+ ValueReference < int > reference = boxedInt ;
147+
148+ boxedInt . Value = 56 ;
149+ Assert . AreEqual ( boxedInt . Value , reference . Value ) ;
150+ }
151+
152+ [ TestMethod ]
153+ public void ArrayCovariance ( )
154+ {
155+ string [ ] array = [ "a" , "b" ] ;
156+ Assert . ThrowsException < ArrayTypeMismatchException > ( ( ) => new ValueReference < object > ( array , 0 ) ) ;
157+
158+ var roRef = new ReadOnlyValueReference < object > ( array , 1 ) ;
159+ Assert . AreEqual ( "b" , roRef . Value ) ;
160+ }
161+
162+ [ TestMethod ]
163+ public void SpanInterop ( )
164+ {
165+ var reference = new ValueReference < int > ( 42 ) ;
166+ Span < int > span = reference ;
167+ Assert . AreEqual ( 1 , span . Length ) ;
168+
169+ Assert . IsTrue ( Unsafe . AreSame ( in reference . Value , in span [ 0 ] ) ) ;
170+ }
171+
172+ [ TestMethod ]
173+ public void ReadOnlySpanInterop ( )
174+ {
175+ ReadOnlyValueReference < int > reference = new ValueReference < int > ( 42 ) ;
176+ ReadOnlySpan < int > span = reference ;
177+ Assert . AreEqual ( 1 , span . Length ) ;
178+
179+ Assert . IsTrue ( Unsafe . AreSame ( in reference . Value , in span [ 0 ] ) ) ;
180+ }
181+
182+ private record MyClass
183+ {
184+ internal int Field ;
185+ internal string ? AnotherField ;
186+ }
187+ }
0 commit comments