1
+ using System ;
2
+ using System . Linq ;
3
+ using System . Collections . Generic ;
4
+ using System . Threading . Tasks ;
5
+ using System . Text . Json ;
6
+ using MySql . Data . MySqlClient ;
7
+ using SciSharp . MySQL . Replication ;
8
+ using SciSharp . MySQL . Replication . Events ;
9
+ using Xunit ;
10
+ using Xunit . Abstractions ;
11
+ using Microsoft . Extensions . Logging ;
12
+ using Microsoft . Extensions . Logging . Console ;
13
+ using System . Collections ;
14
+ using System . Data ;
15
+ using System . Globalization ;
16
+
17
+ namespace Test
18
+ {
19
+ [ Trait ( "Category" , "DataTypes" ) ]
20
+ public class DataTypesTest : IClassFixture < MySQLFixture >
21
+ {
22
+ protected readonly MySQLFixture _mysqlFixture ;
23
+
24
+ public DataTypesTest ( MySQLFixture mysqlFixture )
25
+ {
26
+ _mysqlFixture = mysqlFixture ;
27
+ }
28
+
29
+ [ Fact ]
30
+ public async Task TestDateTimeType ( )
31
+ {
32
+ var currentValue = DateTime . Now ;
33
+ currentValue = new DateTime ( currentValue . Year , currentValue . Month , currentValue . Day , currentValue . Hour , currentValue . Minute , currentValue . Second ) ;
34
+
35
+ await TestDataType < DateTime > ( "datetime_table" , currentValue , currentValue . AddDays ( 1 ) , ( reader , index ) =>
36
+ {
37
+ return reader . GetDateTime ( index ) ;
38
+ } ) ;
39
+ }
40
+
41
+ [ Fact ]
42
+ public async Task TestIntType ( )
43
+ {
44
+ var currentValue = 42 ;
45
+ await TestDataType < int > ( "int_table" , currentValue , currentValue + 10 , ( reader , index ) =>
46
+ {
47
+ return reader . GetInt32 ( index ) ;
48
+ } ) ;
49
+ }
50
+
51
+ //[Fact]
52
+ public async Task TestBigIntType ( )
53
+ {
54
+ var currentValue = 9223372036854775800L ;
55
+ await TestDataType < long > ( "bigint_table" , currentValue , currentValue - 10 , ( reader , index ) =>
56
+ {
57
+ return reader . GetInt64 ( index ) ;
58
+ } ) ;
59
+ }
60
+
61
+ [ Fact ]
62
+ public async Task TestTinyIntType ( )
63
+ {
64
+ var currentValue = ( sbyte ) 42 ;
65
+ await TestDataType < sbyte > ( "tinyint_table" , currentValue , ( sbyte ) ( currentValue + 10 ) , ( reader , index ) =>
66
+ {
67
+ return ( sbyte ) reader . GetByte ( index ) ;
68
+ } ) ;
69
+ }
70
+
71
+ [ Fact ]
72
+ public async Task TestSmallIntType ( )
73
+ {
74
+ var currentValue = ( short ) 1000 ;
75
+ await TestDataType < short > ( "smallint_table" , currentValue , ( short ) ( currentValue + 10 ) , ( reader , index ) =>
76
+ {
77
+ return reader . GetInt16 ( index ) ;
78
+ } ) ;
79
+ }
80
+
81
+ [ Fact ]
82
+ public async Task TestMediumIntType ( )
83
+ {
84
+ var currentValue = 8388000 ; // Close to 2^23 limit for MEDIUMINT
85
+ await TestDataType < int > ( "mediumint_table" , currentValue , currentValue + 10 , ( reader , index ) =>
86
+ {
87
+ return reader . GetInt32 ( index ) ;
88
+ } ) ;
89
+ }
90
+
91
+ //[Fact]
92
+ public async Task TestVarCharType ( )
93
+ {
94
+ var currentValue = "Hello World" ;
95
+ await TestDataType < string > ( "varchar_table" , currentValue , currentValue + " Updated" , ( reader , index ) =>
96
+ {
97
+ return reader . GetString ( index ) ;
98
+ } ) ;
99
+ }
100
+
101
+ //[Fact]
102
+ public async Task TestDecimalType ( )
103
+ {
104
+ var currentValue = 123.45m ;
105
+ await TestDataType < decimal > ( "decimal_table" , currentValue , currentValue + 10.55m , ( reader , index ) =>
106
+ {
107
+ return reader . GetDecimal ( index ) ;
108
+ } ) ;
109
+ }
110
+
111
+ [ Fact ]
112
+ public async Task TestFloatType ( )
113
+ {
114
+ var currentValue = 123.45f ;
115
+ await TestDataType < float > ( "float_table" , currentValue , currentValue + 10.55f , ( reader , index ) =>
116
+ {
117
+ return reader . GetFloat ( index ) ;
118
+ } ) ;
119
+ }
120
+
121
+ //[Fact]
122
+ public async Task TestDoubleType ( )
123
+ {
124
+ var currentValue = 123456.789012 ;
125
+ await TestDataType < double > ( "double_table" , currentValue , currentValue + 100.123 , ( reader , index ) =>
126
+ {
127
+ return reader . GetDouble ( index ) ;
128
+ } ) ;
129
+ }
130
+
131
+ [ Fact ]
132
+ public async Task TestDateType ( )
133
+ {
134
+ var currentValue = DateTime . Today ;
135
+ await TestDataType < DateTime > ( "date_table" , currentValue , currentValue . AddDays ( 5 ) , ( reader , index ) =>
136
+ {
137
+ return reader . GetDateTime ( index ) . Date ;
138
+ } ) ;
139
+ }
140
+
141
+ //[Fact]
142
+ public async Task TestTimeType ( )
143
+ {
144
+ var currentValue = new TimeSpan ( 10 , 30 , 45 ) ;
145
+ await TestDataType < TimeSpan > ( "time_table" , currentValue , currentValue . Add ( new TimeSpan ( 1 , 15 , 30 ) ) , ( reader , index ) =>
146
+ {
147
+ return reader . GetTimeSpan ( index ) ;
148
+ } ) ;
149
+ }
150
+
151
+ //[Fact]
152
+ public async Task TestTimestampType ( )
153
+ {
154
+ var currentValue = DateTime . UtcNow ;
155
+ currentValue = new DateTime ( currentValue . Year , currentValue . Month , currentValue . Day , currentValue . Hour , currentValue . Minute , currentValue . Second , DateTimeKind . Utc ) ;
156
+
157
+ await TestDataType < DateTime > ( "timestamp_table" , currentValue , currentValue . AddHours ( 1 ) , ( reader , index ) =>
158
+ {
159
+ return DateTime . SpecifyKind ( reader . GetDateTime ( index ) , DateTimeKind . Utc ) ;
160
+ } ) ;
161
+ }
162
+
163
+ //[Fact]
164
+ public async Task TestBlobType ( )
165
+ {
166
+ var currentValue = new byte [ ] { 0x01 , 0x02 , 0x03 , 0x04 , 0x05 } ;
167
+ var updateValue = new byte [ ] { 0x06 , 0x07 , 0x08 , 0x09 , 0x0A } ;
168
+
169
+ await TestDataType < byte [ ] > ( "blob_table" , currentValue , updateValue , ( reader , index ) =>
170
+ {
171
+ var length = ( int ) reader . GetBytes ( index , 0 , null , 0 , 0 ) ;
172
+ var buffer = new byte [ length ] ;
173
+ reader . GetBytes ( index , 0 , buffer , 0 , length ) ;
174
+ return buffer ;
175
+ } ) ;
176
+ }
177
+
178
+ //[Fact]
179
+ public async Task TestEnumType ( )
180
+ {
181
+ var currentValue = "SMALL" ;
182
+ await TestDataType < string > ( "enum_table" , currentValue , "MEDIUM" , ( reader , index ) =>
183
+ {
184
+ return reader . GetString ( index ) ;
185
+ } ) ;
186
+ }
187
+
188
+ //[Fact]
189
+ public async Task TestSetType ( )
190
+ {
191
+ var currentValue = "RED,GREEN" ;
192
+ await TestDataType < string > ( "set_table" , currentValue , "RED,BLUE" , ( reader , index ) =>
193
+ {
194
+ return reader . GetString ( index ) ;
195
+ } ) ;
196
+ }
197
+
198
+ //[Fact]
199
+ public async Task TestJsonType ( )
200
+ {
201
+ var currentValue = @"{""name"": ""John"", ""age"": 30}" ;
202
+ var updateValue = @"{""name"": ""Jane"", ""age"": 25, ""city"": ""New York""}" ;
203
+
204
+ await TestDataType < string > ( "json_table" , currentValue , updateValue , ( reader , index ) =>
205
+ {
206
+ return reader . GetString ( index ) ;
207
+ } ) ;
208
+ }
209
+
210
+ //[Fact]
211
+ public async Task TestYearType ( )
212
+ {
213
+ var currentValue = 2023 ;
214
+ await TestDataType < int > ( "year_table" , currentValue , 2024 , ( reader , index ) =>
215
+ {
216
+ return reader . GetInt16 ( index ) ;
217
+ } ) ;
218
+ }
219
+
220
+ private async Task TestDataType < TDateType > ( string tableName , TDateType currentValue , TDateType updateValue , Func < MySqlDataReader , int , TDateType > dataReader )
221
+ {
222
+ // Insert a new row into the table
223
+ var command = _mysqlFixture . CreateCommand ( ) ;
224
+ command . CommandText = $ "insert into { tableName } (value) values (@value);SELECT LAST_INSERT_ID();";
225
+ command . Parameters . AddWithValue ( "@value" , currentValue ) ;
226
+ var id = ( Int32 ) ( UInt64 ) await command . ExecuteScalarAsync ( ) ;
227
+
228
+ // Validate the WriteRowsEvent
229
+ var writeRowsEvent = await _mysqlFixture . ReceiveAsync < WriteRowsEvent > ( ) ;
230
+
231
+ Assert . Equal ( 1 , writeRowsEvent . RowSet . Rows . Count ) ;
232
+ Assert . Equal ( "id" , writeRowsEvent . RowSet . ColumnNames [ 0 ] ) ;
233
+ Assert . Equal ( "value" , writeRowsEvent . RowSet . ColumnNames [ 1 ] ) ;
234
+ var idFromClient = writeRowsEvent . RowSet . Rows [ 0 ] [ 0 ] ;
235
+ var valueFromClient = writeRowsEvent . RowSet . Rows [ 0 ] [ 1 ] ;
236
+ Assert . Equal ( id , ( Int32 ) idFromClient ) ;
237
+ Assert . NotNull ( valueFromClient ) ;
238
+ Assert . Equal ( currentValue , ( TDateType ) valueFromClient ) ;
239
+
240
+ // Validate the data in the database with query
241
+ command = _mysqlFixture . CreateCommand ( ) ;
242
+ command . CommandText = $ "select value from { tableName } where id = @id";
243
+ command . Parameters . AddWithValue ( "@id" , id ) ;
244
+
245
+ MySqlDataReader reader = await command . ExecuteReaderAsync ( ) as MySqlDataReader ;
246
+
247
+ Assert . True ( await reader . ReadAsync ( ) ) ;
248
+
249
+ var savedValue = dataReader ( reader , 0 ) ;
250
+ await reader . CloseAsync ( ) ;
251
+
252
+ Assert . Equal ( currentValue , savedValue ) ;
253
+
254
+ // Update the row
255
+ command = _mysqlFixture . CreateCommand ( ) ;
256
+ command . CommandText = $ "update { tableName } set value=@value where id = @id";
257
+ command . Parameters . AddWithValue ( "@id" , id ) ;
258
+ command . Parameters . AddWithValue ( "@value" , updateValue ) ;
259
+
260
+ Assert . Equal ( 1 , await command . ExecuteNonQueryAsync ( ) ) ;
261
+
262
+ // Validate the UpdateRowsEvent
263
+ var updateRowsEvent = await _mysqlFixture . ReceiveAsync < UpdateRowsEvent > ( ) ;
264
+ Assert . Equal ( 1 , updateRowsEvent . RowSet . Rows . Count ) ;
265
+ Assert . Equal ( "id" , updateRowsEvent . RowSet . ColumnNames [ 0 ] ) ;
266
+ Assert . Equal ( "value" , updateRowsEvent . RowSet . ColumnNames [ 1 ] ) ;
267
+ var idCellValue = updateRowsEvent . RowSet . Rows [ 0 ] [ 0 ] as CellValue ;
268
+ var valueCellValue = updateRowsEvent . RowSet . Rows [ 0 ] [ 1 ] as CellValue ;
269
+ Assert . NotNull ( idCellValue ) ;
270
+ Assert . Equal ( id , ( Int32 ) idCellValue . NewValue ) ;
271
+ Assert . Equal ( id , ( Int32 ) idCellValue . OldValue ) ;
272
+ Assert . NotNull ( valueCellValue ) ;
273
+ Assert . Equal ( currentValue , valueCellValue . OldValue ) ;
274
+ Assert . Equal ( updateValue , valueCellValue . NewValue ) ;
275
+
276
+ // Delete the row
277
+ command = _mysqlFixture . CreateCommand ( ) ;
278
+ command . CommandText = $ "delete from { tableName } where id = @id";
279
+ command . Parameters . AddWithValue ( "@id" , id ) ;
280
+
281
+ await command . ExecuteNonQueryAsync ( ) ;
282
+
283
+ // Validate the DeleteRowsEvent
284
+ var deleteRowsEvent = await _mysqlFixture . ReceiveAsync < DeleteRowsEvent > ( ) ;
285
+ Assert . Equal ( 1 , deleteRowsEvent . RowSet . Rows . Count ) ;
286
+ Assert . Equal ( "id" , deleteRowsEvent . RowSet . ColumnNames [ 0 ] ) ;
287
+ Assert . Equal ( "value" , deleteRowsEvent . RowSet . ColumnNames [ 1 ] ) ;
288
+ idFromClient = deleteRowsEvent . RowSet . Rows [ 0 ] [ 0 ] ;
289
+ valueFromClient = deleteRowsEvent . RowSet . Rows [ 0 ] [ 1 ] ;
290
+ Assert . Equal ( id , ( Int32 ) idFromClient ) ;
291
+ Assert . NotNull ( valueFromClient ) ;
292
+ Assert . Equal ( updateValue , ( TDateType ) valueFromClient ) ;
293
+ }
294
+ }
295
+ }
0 commit comments