Skip to content

Commit 19ac7ba

Browse files
CopilotFrankBakkerNlRick-van-DamCopilot
authored
Fix duplicate SensorEntities registration in AddHomeAssistantGenerated (#1316)
* Fix duplicate SensorEntities registration in AddHomeAssistantGenerated Co-authored-by: FrankBakkerNl <[email protected]> * Update src/HassModel/NetDaemon.HassModel.Tests/CodeGenerator/HelpersGeneratorTest.cs Co-authored-by: Copilot <[email protected]> * Add missing using System.Text.RegularExpressions in HelpersGeneratorTest Co-authored-by: Rick-van-Dam <[email protected]> --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: FrankBakkerNl <[email protected]> Co-authored-by: Rick van Dam <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent bde37bf commit 19ac7ba

File tree

2 files changed

+77
-2
lines changed

2 files changed

+77
-2
lines changed

src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/HelpersGenerator.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ private static MethodDeclarationSyntax BuildAddHomeAssistantGenerated(IEnumerabl
6565
private static IEnumerable<string> GetInjectableTypes(IEnumerable<EntityDomainMetadata> domains, IEnumerable<HassServiceDomain> orderedServiceDomains) =>
6666
[
6767
EntitiesClassName,
68-
.. domains.Select(d => d.EntitiesForDomainClassName),
68+
.. domains.Select(d => d.EntitiesForDomainClassName).Distinct(),
6969
ServicesClassName,
70-
..orderedServiceDomains.Select(d => GetServicesTypeName(d.Domain))
70+
..orderedServiceDomains.Select(d => GetServicesTypeName(d.Domain)).Distinct()
7171
];
7272
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
using System.Text.RegularExpressions;
2+
using NetDaemon.Client.HomeAssistant.Model;
3+
using NetDaemon.HassModel.CodeGenerator;
4+
using NetDaemon.HassModel.CodeGenerator.CodeGeneration;
5+
6+
namespace NetDaemon.HassModel.Tests.CodeGenerator;
7+
8+
public class HelpersGeneratorTest
9+
{
10+
[Fact]
11+
public void AddHomeAssistantGenerated_ShouldNotRegisterDuplicateEntityClasses()
12+
{
13+
// Arrange: Create test data that would lead to duplicate SensorEntities registrations
14+
var states = new HassState[]
15+
{
16+
// Non-numeric sensor (no unit_of_measurement)
17+
new() { EntityId = "sensor.simple_text", Attributes = new Dictionary<string, object>() },
18+
19+
// Numeric sensor (has unit_of_measurement)
20+
new() { EntityId = "sensor.temperature", Attributes = new Dictionary<string, object> { ["unit_of_measurement"] = "°C" } }
21+
};
22+
23+
// Act: Generate metadata which creates both numeric and non-numeric sensor domains
24+
var metaData = EntityMetaDataGenerator.GetEntityDomainMetaData(states);
25+
26+
// Both should have the same EntitiesForDomainClassName
27+
var sensorDomains = metaData.Domains.Where(d => d.Domain == "sensor").ToList();
28+
sensorDomains.Should().HaveCount(2, "there should be both numeric and non-numeric sensor domains");
29+
sensorDomains.Should().AllSatisfy(d => d.EntitiesForDomainClassName.Should().Be("SensorEntities"));
30+
31+
// Generate the extension method code
32+
var generatedMembers = HelpersGenerator.Generate(metaData.Domains, []).ToList();
33+
var generatedCode = generatedMembers.First().ToString();
34+
35+
// Assert: The generated code should not contain duplicate SensorEntities registrations
36+
var sensorEntitiesMatches = Regex.Matches(
37+
generatedCode,
38+
@"serviceCollection\.AddTransient<SensorEntities>\(\);");
39+
40+
sensorEntitiesMatches.Should().HaveCount(1, "SensorEntities should only be registered once, not duplicated");
41+
}
42+
43+
[Fact]
44+
public void AddHomeAssistantGenerated_ShouldRegisterAllUniqueEntityClasses()
45+
{
46+
// Arrange: Create test data with different domains
47+
var states = new HassState[]
48+
{
49+
new() { EntityId = "sensor.temperature", Attributes = new Dictionary<string, object> { ["unit_of_measurement"] = "°C" } },
50+
new() { EntityId = "light.living_room", Attributes = new Dictionary<string, object>() },
51+
new() { EntityId = "switch.kitchen", Attributes = new Dictionary<string, object>() }
52+
};
53+
54+
// Act: Generate metadata
55+
var metaData = EntityMetaDataGenerator.GetEntityDomainMetaData(states);
56+
57+
// Generate the extension method code
58+
var generatedMembers = HelpersGenerator.Generate(metaData.Domains, []).ToList();
59+
var generatedCode = generatedMembers.First().ToString();
60+
61+
// Assert: Each domain should be registered exactly once
62+
generatedCode.Should().Contain("serviceCollection.AddTransient<SensorEntities>();");
63+
generatedCode.Should().Contain("serviceCollection.AddTransient<LightEntities>();");
64+
generatedCode.Should().Contain("serviceCollection.AddTransient<SwitchEntities>();");
65+
66+
// Verify no duplicates
67+
var sensorMatches = Regex.Matches(generatedCode, @"serviceCollection\.AddTransient<SensorEntities>\(\);");
68+
var lightMatches = Regex.Matches(generatedCode, @"serviceCollection\.AddTransient<LightEntities>\(\);");
69+
var switchMatches = Regex.Matches(generatedCode, @"serviceCollection\.AddTransient<SwitchEntities>\(\);");
70+
71+
sensorMatches.Should().HaveCount(1);
72+
lightMatches.Should().HaveCount(1);
73+
switchMatches.Should().HaveCount(1);
74+
}
75+
}

0 commit comments

Comments
 (0)