Skip to content

Commit 363e613

Browse files
committed
Add more tests, update error types
1 parent 10af1f2 commit 363e613

2 files changed

Lines changed: 147 additions & 12 deletions

File tree

PowerSync/PowerSync.Common/DB/Schema/Attributes/AttributeParser.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public AttributeParser(Type type)
2121
_tableAttr = _type.GetCustomAttribute<TableAttribute>();
2222
if (_tableAttr == null)
2323
{
24-
throw new CustomAttributeFormatException("Table classes must be marked with TableAttribute.");
24+
throw new InvalidOperationException("Table classes must be marked with TableAttribute.");
2525
}
2626
}
2727

@@ -167,14 +167,14 @@ public TableOptions ParseTableOptions()
167167

168168
if (trackPrevious.HasFlag(TrackPrevious.Columns) && trackPrevious.HasFlag(TrackPrevious.Table))
169169
{
170-
throw new CustomAttributeFormatException("Cannot specify both TrackPrevious.Columns and TrackPrevious.Table on the same table.");
170+
throw new InvalidOperationException("Cannot specify both TrackPrevious.Columns and TrackPrevious.Table on the same table.");
171171
}
172172

173173
if (!trackPrevious.HasFlag(TrackPrevious.Columns)
174174
&& !trackPrevious.HasFlag(TrackPrevious.Table)
175175
&& trackPrevious.HasFlag(TrackPrevious.OnlyWhenChanged))
176176
{
177-
throw new CustomAttributeFormatException("Cannot specify TrackPrevious.OnlyWhenChanged without also specifying either TrackPrevious.Columns or TrackPrevious.Table.");
177+
throw new InvalidOperationException("Cannot specify TrackPrevious.OnlyWhenChanged without also specifying either TrackPrevious.Columns or TrackPrevious.Table.");
178178
}
179179

180180
bool trackWholeTable = _tableAttr.TrackPreviousValues.HasFlag(TrackPrevious.Table);

Tests/PowerSync/PowerSync.Common.Tests/DB/SchemaTests.cs

Lines changed: 144 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ namespace PowerSync.Common.Tests.DB.Schema;
1212
/// </summary>
1313
public class SchemaTests
1414
{
15+
private void TestParser(Type type, CompiledTable expected)
16+
{
17+
var parser = new AttributeParser(type);
18+
var table = parser.ParseTable().Compile();
19+
Assert.Equivalent(expected, table, strict: true);
20+
}
21+
1522
[
1623
Table(
1724
"test_assets",
@@ -132,6 +139,14 @@ public void AttributeParser_Products_Test()
132139
TestParser(typeof(Product), expected);
133140
}
134141

142+
enum LogLevel
143+
{
144+
Info,
145+
Debug,
146+
Warning,
147+
Error
148+
}
149+
135150
[
136151
Table(
137152
"test_logs",
@@ -141,11 +156,22 @@ public void AttributeParser_Products_Test()
141156
IgnoreEmptyUpdates = true
142157
)
143158
]
144-
class Logs
159+
class Log
145160
{
146-
public string id { get; set; }
147-
public string description { get; set; }
148-
public DateTimeOffset timestamp { get; set; }
161+
[Column("id")]
162+
public string LogId { get; set; }
163+
164+
[Column("description")]
165+
public string Description { get; set; }
166+
167+
[Column("timestamp")]
168+
public DateTimeOffset Timestamp { get; set; }
169+
170+
[Column("log_level")]
171+
public LogLevel LogLevel { get; set; }
172+
173+
[Ignored]
174+
public string LogLevelString { get { return LogLevel.ToString(); } }
149175
}
150176

151177
[Fact]
@@ -157,6 +183,7 @@ public void AttributeParser_Logs_Test()
157183
{
158184
["description"] = ColumnType.Text,
159185
["timestamp"] = ColumnType.Text,
186+
["log_level"] = ColumnType.Integer,
160187
},
161188
new TableOptions
162189
{
@@ -170,13 +197,121 @@ public void AttributeParser_Logs_Test()
170197
}
171198
);
172199

173-
TestParser(typeof(Logs), expected);
200+
TestParser(typeof(Log), expected);
174201
}
175202

176-
private void TestParser(Type type, CompiledTable expected)
203+
class Invalid1 { public string id { get; set; } }
204+
[Fact]
205+
public async void AttributeParser_InvalidSchema_1()
177206
{
178-
var parser = new AttributeParser(type);
179-
var table = parser.ParseTable().Compile();
180-
Assert.Equivalent(expected, table, strict: true);
207+
var ex = await Assert.ThrowsAsync<InvalidOperationException>(async () =>
208+
{
209+
new AttributeParser(typeof(Invalid1)).ParseTable();
210+
});
211+
Assert.Contains("must be marked with TableAttribute", ex.Message);
212+
}
213+
214+
[Table("invalid")]
215+
class Invalid2 { }
216+
[Fact]
217+
public async void AttributeParser_InvalidSchema_2()
218+
{
219+
var ex = await Assert.ThrowsAsync<InvalidOperationException>(async () =>
220+
{
221+
new AttributeParser(typeof(Invalid2)).ParseTable();
222+
});
223+
Assert.Contains("'id' property is required", ex.Message);
224+
}
225+
226+
[Table("invalid")]
227+
class Invalid3 { public int id { get; set; } }
228+
[Fact]
229+
public async void AttributeParser_InvalidSchema_3()
230+
{
231+
var ex = await Assert.ThrowsAsync<InvalidOperationException>(async () =>
232+
{
233+
new AttributeParser(typeof(Invalid3)).ParseTable();
234+
});
235+
Assert.Contains("must be of type string", ex.Message);
236+
}
237+
238+
[Table("invalid")]
239+
class Invalid4
240+
{
241+
[Column(ColumnType = ColumnType.Real)]
242+
public string id { get; set; }
243+
}
244+
[Fact]
245+
public async void AttributeParser_InvalidSchema_4()
246+
{
247+
var ex = await Assert.ThrowsAsync<InvalidOperationException>(async () =>
248+
{
249+
new AttributeParser(typeof(Invalid4)).ParseTable();
250+
});
251+
Assert.Contains("must have ColumnType set to ColumnType.Text or ColumnType.Inferred", ex.Message);
252+
}
253+
254+
[Table("invalid")]
255+
class Invalid5
256+
{
257+
public string id { get; set; }
258+
public Invalid1 invalid_type { get; set; }
259+
}
260+
[Fact]
261+
public async void AttributeParser_InvalidSchema_5()
262+
{
263+
var ex = await Assert.ThrowsAsync<InvalidOperationException>(async () =>
264+
{
265+
new AttributeParser(typeof(Invalid5)).ParseTable();
266+
});
267+
Assert.Contains("Unable to automatically infer ColumnType", ex.Message);
268+
}
269+
270+
[Table("invalid", TrackPreviousValues = TrackPrevious.Columns | TrackPrevious.Table)]
271+
class Invalid6
272+
{
273+
public string id { get; set; }
274+
}
275+
[Fact]
276+
public async void AttributeParser_InvalidSchema_6()
277+
{
278+
var ex = await Assert.ThrowsAsync<InvalidOperationException>(async () =>
279+
{
280+
new AttributeParser(typeof(Invalid6)).ParseTable();
281+
});
282+
Assert.Contains("Cannot specify both TrackPrevious.Columns and TrackPrevious.Table", ex.Message);
283+
}
284+
285+
[Table("invalid", TrackPreviousValues = TrackPrevious.OnlyWhenChanged)]
286+
class Invalid7
287+
{
288+
public string id { get; set; }
289+
}
290+
[Fact]
291+
public async void AttributeParser_InvalidSchema_7()
292+
{
293+
var ex = await Assert.ThrowsAsync<InvalidOperationException>(async () =>
294+
{
295+
new AttributeParser(typeof(Invalid7)).ParseTable();
296+
});
297+
Assert.Contains("Cannot specify TrackPrevious.OnlyWhenChanged without also specifying", ex.Message);
298+
}
299+
300+
[Fact]
301+
public async void AttributeParser_TypeMap_CustomRegistered()
302+
{
303+
// Log has Column aliases
304+
new AttributeParser(typeof(Log)).RegisterDapperTypeMap();
305+
var typeMap = Dapper.SqlMapper.GetTypeMap(typeof(Log));
306+
Assert.False(typeMap is Dapper.DefaultTypeMap);
307+
}
308+
309+
[Fact]
310+
public async void AttributeParser_TypeMap_DefaultRegistered()
311+
{
312+
// Asset has no Column aliases
313+
new AttributeParser(typeof(Asset)).RegisterDapperTypeMap();
314+
var typeMap = Dapper.SqlMapper.GetTypeMap(typeof(Asset));
315+
Assert.True(typeMap is Dapper.DefaultTypeMap);
181316
}
182317
}

0 commit comments

Comments
 (0)