Skip to content

Commit a7798bd

Browse files
test: expand branch coverage across renderers, differs, generators and helpers
1 parent cb2a2d7 commit a7798bd

29 files changed

Lines changed: 8448 additions & 159 deletions

src/Eftdb.Design/TimescaleCSharpMigrationOperationGenerator.cs

Lines changed: 13 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,70 +13,51 @@ protected override void Generate(MigrationOperation operation, IndentedStringBui
1313
ArgumentNullException.ThrowIfNull(operation);
1414
ArgumentNullException.ThrowIfNull(builder);
1515

16-
HypertableCSharpGenerator? hypertableCSharpGenerator = null;
17-
ReorderPolicyCSharpGenerator? reorderPolicyCSharpGenerator = null;
18-
RetentionPolicyCSharpGenerator? retentionPolicyCSharpGenerator = null;
19-
ContinuousAggregateCSharpGenerator? continuousAggregateCSharpGenerator = null;
20-
ContinuousAggregatePolicyCSharpGenerator? continuousAggregatePolicyCSharpGenerator = null;
21-
2216
switch (operation)
2317
{
2418
case CreateHypertableOperation create:
25-
hypertableCSharpGenerator ??= new(Dependencies.CSharpHelper);
26-
hypertableCSharpGenerator.Generate(create, builder);
19+
new HypertableCSharpGenerator(Dependencies.CSharpHelper).Generate(create, builder);
2720
return;
2821
case AlterHypertableOperation alter:
29-
hypertableCSharpGenerator ??= new(Dependencies.CSharpHelper);
30-
hypertableCSharpGenerator.Generate(alter, builder);
22+
new HypertableCSharpGenerator(Dependencies.CSharpHelper).Generate(alter, builder);
3123
return;
3224

3325
case AddReorderPolicyOperation addReorder:
34-
reorderPolicyCSharpGenerator ??= new(Dependencies.CSharpHelper);
35-
reorderPolicyCSharpGenerator.Generate(addReorder, builder);
26+
new ReorderPolicyCSharpGenerator(Dependencies.CSharpHelper).Generate(addReorder, builder);
3627
return;
3728
case AlterReorderPolicyOperation alterReorder:
38-
reorderPolicyCSharpGenerator ??= new(Dependencies.CSharpHelper);
39-
reorderPolicyCSharpGenerator.Generate(alterReorder, builder);
29+
new ReorderPolicyCSharpGenerator(Dependencies.CSharpHelper).Generate(alterReorder, builder);
4030
return;
4131
case DropReorderPolicyOperation dropReorder:
42-
reorderPolicyCSharpGenerator ??= new(Dependencies.CSharpHelper);
43-
reorderPolicyCSharpGenerator.Generate(dropReorder, builder);
32+
new ReorderPolicyCSharpGenerator(Dependencies.CSharpHelper).Generate(dropReorder, builder);
4433
return;
4534

4635
case AddRetentionPolicyOperation addRetention:
47-
retentionPolicyCSharpGenerator ??= new(Dependencies.CSharpHelper);
48-
retentionPolicyCSharpGenerator.Generate(addRetention, builder);
36+
new RetentionPolicyCSharpGenerator(Dependencies.CSharpHelper).Generate(addRetention, builder);
4937
return;
5038
case AlterRetentionPolicyOperation alterRetention:
51-
retentionPolicyCSharpGenerator ??= new(Dependencies.CSharpHelper);
52-
retentionPolicyCSharpGenerator.Generate(alterRetention, builder);
39+
new RetentionPolicyCSharpGenerator(Dependencies.CSharpHelper).Generate(alterRetention, builder);
5340
return;
5441
case DropRetentionPolicyOperation dropRetention:
55-
retentionPolicyCSharpGenerator ??= new(Dependencies.CSharpHelper);
56-
retentionPolicyCSharpGenerator.Generate(dropRetention, builder);
42+
new RetentionPolicyCSharpGenerator(Dependencies.CSharpHelper).Generate(dropRetention, builder);
5743
return;
5844

5945
case CreateContinuousAggregateOperation createContinuousAggregate:
60-
continuousAggregateCSharpGenerator ??= new(Dependencies.CSharpHelper);
61-
continuousAggregateCSharpGenerator.Generate(createContinuousAggregate, builder);
46+
new ContinuousAggregateCSharpGenerator(Dependencies.CSharpHelper).Generate(createContinuousAggregate, builder);
6247
return;
6348
case AlterContinuousAggregateOperation alterContinuousAggregate:
64-
continuousAggregateCSharpGenerator ??= new(Dependencies.CSharpHelper);
65-
continuousAggregateCSharpGenerator.Generate(alterContinuousAggregate, builder);
49+
new ContinuousAggregateCSharpGenerator(Dependencies.CSharpHelper).Generate(alterContinuousAggregate, builder);
6650
return;
6751
case DropContinuousAggregateOperation dropContinuousAggregate:
68-
continuousAggregateCSharpGenerator ??= new(Dependencies.CSharpHelper);
69-
continuousAggregateCSharpGenerator.Generate(dropContinuousAggregate, builder);
52+
new ContinuousAggregateCSharpGenerator(Dependencies.CSharpHelper).Generate(dropContinuousAggregate, builder);
7053
return;
7154

7255
case AddContinuousAggregatePolicyOperation addContinuousAggregatePolicy:
73-
continuousAggregatePolicyCSharpGenerator ??= new(Dependencies.CSharpHelper);
74-
continuousAggregatePolicyCSharpGenerator.Generate(addContinuousAggregatePolicy, builder);
56+
new ContinuousAggregatePolicyCSharpGenerator(Dependencies.CSharpHelper).Generate(addContinuousAggregatePolicy, builder);
7557
return;
7658

7759
case RemoveContinuousAggregatePolicyOperation removeContinuousAggregatePolicy:
78-
continuousAggregatePolicyCSharpGenerator ??= new(Dependencies.CSharpHelper);
79-
continuousAggregatePolicyCSharpGenerator.Generate(removeContinuousAggregatePolicy, builder);
60+
new ContinuousAggregatePolicyCSharpGenerator(Dependencies.CSharpHelper).Generate(removeContinuousAggregatePolicy, builder);
8061
return;
8162

8263
default:

tests/Eftdb.Tests/Configuration/RetentionPolicyAttributeTests.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,28 @@ public void AllProperties_CanBeSetTogether()
230230

231231
#endregion
232232

233+
#region Should_Throw_When_DropAfter_WhitespaceOnly
234+
235+
[Fact]
236+
public void Constructor2_With_WhitespaceOnly_DropAfter_ThrowsInvalidOperationException()
237+
{
238+
// Arrange & Act & Assert
239+
InvalidOperationException ex = Assert.Throws<InvalidOperationException>(
240+
() => new RetentionPolicyAttribute(dropAfter: " ", dropCreatedBefore: null));
241+
Assert.Contains("exactly one", ex.Message, StringComparison.OrdinalIgnoreCase);
242+
}
243+
244+
[Fact]
245+
public void Constructor2_With_WhitespaceOnly_DropCreatedBefore_ThrowsInvalidOperationException()
246+
{
247+
// Arrange & Act & Assert
248+
InvalidOperationException ex = Assert.Throws<InvalidOperationException>(
249+
() => new RetentionPolicyAttribute(dropAfter: null, dropCreatedBefore: "\t "));
250+
Assert.Contains("exactly one", ex.Message, StringComparison.OrdinalIgnoreCase);
251+
}
252+
253+
#endregion
254+
233255
#region Constructor2 Empty and Whitespace String Tests
234256

235257
[Fact]

tests/Eftdb.Tests/Conventions/ContinuousAggregateConventionTests.cs

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -960,4 +960,156 @@ public void Should_Not_Set_GroupByColumns_Annotation_Without_Attributes()
960960
}
961961

962962
#endregion
963+
964+
#region Should_Not_Set_TimeBucket_Annotations_When_TimeBucket_Attribute_Absent
965+
966+
[Hypertable("Timestamp")]
967+
private class NoTimeBucketSourceEntity
968+
{
969+
public DateTime Timestamp { get; set; }
970+
public double Value { get; set; }
971+
}
972+
973+
[ContinuousAggregate(MaterializedViewName = "no_timebucket_view", ParentName = "no_timebucket_source")]
974+
private class NoTimeBucketCaEntity
975+
{
976+
[Aggregate(EAggregateFunction.Avg, "Value")]
977+
public double AvgValue { get; set; }
978+
}
979+
980+
private class NoTimeBucketContext : DbContext
981+
{
982+
public DbSet<NoTimeBucketSourceEntity> Sources => Set<NoTimeBucketSourceEntity>();
983+
public DbSet<NoTimeBucketCaEntity> Aggregates => Set<NoTimeBucketCaEntity>();
984+
985+
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
986+
=> optionsBuilder.UseNpgsql("Host=localhost;Database=test;Username=test;Password=test")
987+
.UseTimescaleDb();
988+
989+
protected override void OnModelCreating(ModelBuilder modelBuilder)
990+
{
991+
modelBuilder.Entity<NoTimeBucketSourceEntity>(entity =>
992+
{
993+
entity.HasNoKey();
994+
entity.ToTable("no_timebucket_source");
995+
});
996+
997+
modelBuilder.Entity<NoTimeBucketCaEntity>(entity =>
998+
{
999+
entity.HasNoKey();
1000+
});
1001+
}
1002+
}
1003+
1004+
[Fact]
1005+
public void Should_Not_Set_TimeBucket_Annotations_When_TimeBucket_Attribute_Absent()
1006+
{
1007+
using NoTimeBucketContext context = new();
1008+
1009+
// Act
1010+
IModel model = GetModel(context);
1011+
IEntityType entityType = model.FindEntityType(typeof(NoTimeBucketCaEntity))!;
1012+
1013+
// Assert
1014+
Assert.NotNull(entityType.FindAnnotation(ContinuousAggregateAnnotations.MaterializedViewName));
1015+
Assert.Null(entityType.FindAnnotation(ContinuousAggregateAnnotations.TimeBucketWidth));
1016+
Assert.Null(entityType.FindAnnotation(ContinuousAggregateAnnotations.TimeBucketSourceColumn));
1017+
}
1018+
1019+
#endregion
1020+
1021+
#region Should_Use_Property_Name_As_Source_Column_When_AggregateAttribute_SourceColumn_Not_Provided
1022+
1023+
[Hypertable("Timestamp")]
1024+
private class DefaultSourceColSourceEntity
1025+
{
1026+
public DateTime Timestamp { get; set; }
1027+
public double Revenue { get; set; }
1028+
}
1029+
1030+
[ContinuousAggregate(MaterializedViewName = "default_src_col_view", ParentName = "default_src_col_source")]
1031+
[TimeBucket("1 day", "Timestamp")]
1032+
private class DefaultSourceColCaEntity
1033+
{
1034+
[Aggregate(EAggregateFunction.Count)]
1035+
public long EventCount { get; set; }
1036+
}
1037+
1038+
private class DefaultSourceColContext : DbContext
1039+
{
1040+
public DbSet<DefaultSourceColSourceEntity> Sources => Set<DefaultSourceColSourceEntity>();
1041+
public DbSet<DefaultSourceColCaEntity> Aggregates => Set<DefaultSourceColCaEntity>();
1042+
1043+
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
1044+
=> optionsBuilder.UseNpgsql("Host=localhost;Database=test;Username=test;Password=test")
1045+
.UseTimescaleDb();
1046+
1047+
protected override void OnModelCreating(ModelBuilder modelBuilder)
1048+
{
1049+
modelBuilder.Entity<DefaultSourceColSourceEntity>(entity =>
1050+
{
1051+
entity.HasNoKey();
1052+
entity.ToTable("default_src_col_source");
1053+
});
1054+
1055+
modelBuilder.Entity<DefaultSourceColCaEntity>(entity =>
1056+
{
1057+
entity.HasNoKey();
1058+
});
1059+
}
1060+
}
1061+
1062+
[Fact]
1063+
public void Should_Use_Property_Name_As_Source_Column_When_AggregateAttribute_SourceColumn_Not_Provided()
1064+
{
1065+
// Arrange
1066+
using DefaultSourceColContext context = new();
1067+
1068+
// Act
1069+
IModel model = GetModel(context);
1070+
IEntityType entityType = model.FindEntityType(typeof(DefaultSourceColCaEntity))!;
1071+
List<string>? aggregateFunctions = entityType
1072+
.FindAnnotation(ContinuousAggregateAnnotations.AggregateFunctions)?.Value as List<string>;
1073+
1074+
// Assert
1075+
Assert.NotNull(aggregateFunctions);
1076+
Assert.Contains(aggregateFunctions, e => e.StartsWith("EventCount:Count:*", StringComparison.Ordinal));
1077+
}
1078+
1079+
#endregion
1080+
1081+
#region Should_Skip_CA_Annotations_For_Property_Bag_Entity
1082+
1083+
private class PropertyBagCaContext : DbContext
1084+
{
1085+
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
1086+
=> optionsBuilder.UseNpgsql("Host=localhost;Database=test;Username=test;Password=test")
1087+
.UseTimescaleDb();
1088+
1089+
protected override void OnModelCreating(ModelBuilder modelBuilder)
1090+
{
1091+
modelBuilder.Entity("PropertyBagCaTestEntity", b =>
1092+
{
1093+
b.HasNoKey();
1094+
b.ToTable("prop_bag_ca_test");
1095+
b.Property<int>("Id");
1096+
});
1097+
}
1098+
}
1099+
1100+
[Fact]
1101+
public void Should_Skip_CA_Annotations_For_Property_Bag_Entity()
1102+
{
1103+
// Arrange
1104+
using PropertyBagCaContext context = new();
1105+
IModel model = GetModel(context);
1106+
IEntityType entityType = model.FindEntityType("PropertyBagCaTestEntity")!;
1107+
1108+
// Act + Assert
1109+
Assert.NotNull(entityType);
1110+
Assert.Null(entityType.FindAnnotation(ContinuousAggregateAnnotations.MaterializedViewName));
1111+
Assert.Null(entityType.FindAnnotation(ContinuousAggregateAnnotations.ParentName));
1112+
}
1113+
1114+
#endregion
9631115
}

0 commit comments

Comments
 (0)