Skip to content

Commit b9f8479

Browse files
authored
Merge pull request #24 from swagfin/feature/performance-grade-optimization
Feature/performance grade optimization
2 parents e012c2e + d7f15bd commit b9f8479

23 files changed

Lines changed: 2422 additions & 359 deletions

ObjectSemantics.NET.Tests/CognitiveMapTests.cs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,83 @@ public void Library_Entry_Point_String_Extension_Should_Work(string personName)
3333
Assert.Equal($"I am {personName}!", generatedTemplate);
3434
}
3535

36+
[Fact]
37+
public void Property_Of_Object_Should_Be_Mapped()
38+
{
39+
CustomerPayment customerPayment = new CustomerPayment
40+
{
41+
Amount = 100_000_000,
42+
Customer = new Customer
43+
{
44+
CompanyName = "CRUDSOFT TECHNOLOGIES"
45+
}
46+
};
47+
string generatedTemplate = "Paid Amount: {{ Amount:N2 }} By {{ Customer.CompanyName }}".Map(customerPayment);
48+
Assert.Equal("Paid Amount: 100,000,000.00 By CRUDSOFT TECHNOLOGIES", generatedTemplate);
49+
}
50+
51+
[Fact]
52+
public void Nested_Property_Should_Be_Empty_When_Parent_Object_Is_Null()
53+
{
54+
CustomerPayment customerPayment = new CustomerPayment
55+
{
56+
Amount = 100_000_000,
57+
Customer = null
58+
};
59+
60+
string generatedTemplate = "Paid Amount: {{ Amount:N2 }} By {{ Customer.CompanyName }}".Map(customerPayment);
61+
Assert.Equal("Paid Amount: 100,000,000.00 By ", generatedTemplate);
62+
}
63+
64+
[Fact]
65+
public void Nested_Property_Should_Be_Empty_When_Target_Property_Is_Null()
66+
{
67+
CustomerPayment customerPayment = new CustomerPayment
68+
{
69+
Amount = 100_000_000,
70+
Customer = new Customer
71+
{
72+
CompanyName = null
73+
}
74+
};
75+
76+
string generatedTemplate = "Paid Amount: {{ Amount:N2 }} By {{ Customer.CompanyName }}".Map(customerPayment);
77+
Assert.Equal("Paid Amount: 100,000,000.00 By ", generatedTemplate);
78+
}
79+
80+
[Fact]
81+
public void Deeply_Nested_Property_Should_Be_Mapped()
82+
{
83+
CustomerPayment customerPayment = new CustomerPayment
84+
{
85+
Amount = 100_000_000,
86+
Customer = new Customer
87+
{
88+
BankingDetail = new CustomerBankingDetail
89+
{
90+
BankName = "KCB BANK"
91+
}
92+
}
93+
};
94+
95+
string generatedTemplate = "Paid Amount: {{ Amount:N2 }} Via {{ Customer.BankingDetail.BankName }}".Map(customerPayment);
96+
Assert.Equal("Paid Amount: 100,000,000.00 Via KCB BANK", generatedTemplate);
97+
}
98+
99+
[Fact]
100+
public void Deeply_Nested_Property_Should_Be_Empty_When_Object_Is_Null()
101+
{
102+
CustomerPayment customerPayment = new CustomerPayment
103+
{
104+
Amount = 100_000_000,
105+
Customer = null
106+
};
107+
108+
string generatedTemplate = "Paid Amount: {{ Amount:N2 }} Via {{ Customer.BankingDetail.BankName }}".Map(customerPayment);
109+
Assert.Equal("Paid Amount: 100,000,000.00 Via ", generatedTemplate);
110+
}
111+
112+
36113
[Fact]
37114
public void Additional_Headers_Should_Also_Be_Mapped()
38115
{
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
using ObjectSemantics.NET.Tests.MoqModels;
2+
using System.Collections.Generic;
3+
using Xunit;
4+
5+
namespace ObjectSemantics.NET.Tests
6+
{
7+
public class ExpressionFunctionTests
8+
{
9+
[Fact]
10+
public void Should_Sum_Collection_Path()
11+
{
12+
OrderEmailModel model = new OrderEmailModel
13+
{
14+
Customer = new OrderCustomer
15+
{
16+
Payments = new List<OrderPayment>
17+
{
18+
new OrderPayment { Amount = 1000 },
19+
new OrderPayment { Amount = 2000.75m },
20+
new OrderPayment { Amount = 999.25m }
21+
}
22+
}
23+
};
24+
25+
string result = model.Map("{{ __sum(Customer.Payments.Amount):N2 }}");
26+
Assert.Equal("4,000.00", result);
27+
}
28+
29+
[Fact]
30+
public void Should_Average_Collection_Path_With_Single_Underscore()
31+
{
32+
OrderEmailModel model = new OrderEmailModel
33+
{
34+
Customer = new OrderCustomer
35+
{
36+
Payments = new List<OrderPayment>
37+
{
38+
new OrderPayment { PaidAmount = 300 },
39+
new OrderPayment { PaidAmount = 900 },
40+
new OrderPayment { PaidAmount = 1200 }
41+
}
42+
}
43+
};
44+
45+
string result = model.Map("{{ _avg(Customer.Payments.PaidAmount):N2 }}");
46+
Assert.Equal("800.00", result);
47+
}
48+
49+
[Fact]
50+
public void Should_Calculate_Property_Expression()
51+
{
52+
OrderEmailModel model = new OrderEmailModel
53+
{
54+
PaidAmount = 10000,
55+
Customer = new OrderCustomer
56+
{
57+
CreditLimit = 4500
58+
}
59+
};
60+
61+
string result = model.Map("{{ __calc(PaidAmount - Customer.CreditLimit):N2 }}");
62+
Assert.Equal("5,500.00", result);
63+
}
64+
65+
[Fact]
66+
public void Should_Calculate_Expression_Including_Parentheses_And_Decimals()
67+
{
68+
OrderEmailModel model = new OrderEmailModel
69+
{
70+
Subtotal = 1000,
71+
Tax = 160
72+
};
73+
74+
string result = model.Map("{{ __calc((Subtotal + Tax) * 0.5):N2 }}");
75+
Assert.Equal("580.00", result);
76+
}
77+
78+
[Fact]
79+
public void Should_Calculate_Count_Min_And_Max_Aggregates()
80+
{
81+
OrderEmailModel model = new OrderEmailModel
82+
{
83+
Customer = new OrderCustomer
84+
{
85+
Payments = new List<OrderPayment>
86+
{
87+
new OrderPayment { Amount = 700 },
88+
new OrderPayment { Amount = 200 },
89+
new OrderPayment { Amount = 1100 }
90+
}
91+
}
92+
};
93+
94+
string template = "{{ __count(Customer.Payments.Amount) }}|{{ __min(Customer.Payments.Amount):N2 }}|{{ __max(Customer.Payments.Amount):N2 }}";
95+
string result = model.Map(template);
96+
Assert.Equal("3|200.00|1,100.00", result);
97+
}
98+
99+
[Fact]
100+
public void Should_Calculate_Per_Row_Expression_Inside_Loop()
101+
{
102+
OrderEmailModel model = new OrderEmailModel
103+
{
104+
Items = new List<OrderLineItem>
105+
{
106+
new OrderLineItem { Quantity = 2, UnitPrice = 350 },
107+
new OrderLineItem { Quantity = 3, UnitPrice = 100.5m }
108+
}
109+
};
110+
111+
string template = "{{ #foreach(Items) }}[{{ __calc(Quantity * UnitPrice):N2 }}]{{ #endforeach }}";
112+
string result = model.Map(template);
113+
114+
Assert.Equal("[700.00][301.50]", result);
115+
}
116+
117+
[Fact]
118+
public void Should_Render_Empty_When_Calc_Expression_Is_Invalid()
119+
{
120+
OrderEmailModel model = new OrderEmailModel
121+
{
122+
PaidAmount = 5000,
123+
Customer = new OrderCustomer
124+
{
125+
CreditLimit = 1000
126+
}
127+
};
128+
129+
string result = model.Map("A{{ __calc(PaidAmount - UnknownValue):N2 }}B");
130+
Assert.Equal("AB", result);
131+
}
132+
133+
[Fact]
134+
public void Should_Render_Empty_For_Unknown_Aggregate_Path()
135+
{
136+
OrderEmailModel model = new OrderEmailModel
137+
{
138+
Customer = new OrderCustomer
139+
{
140+
Payments = new List<OrderPayment>
141+
{
142+
new OrderPayment { Amount = 100 }
143+
}
144+
}
145+
};
146+
147+
string result = model.Map("{{ __sum(Customer.UnknownPayments.Amount) }}|{{ __avg(Customer.UnknownPayments.Amount) }}|{{ __count(Customer.UnknownPayments.Amount) }}|{{ __min(Customer.UnknownPayments.Amount) }}|{{ __max(Customer.UnknownPayments.Amount) }}");
148+
Assert.Equal("||||", result);
149+
}
150+
151+
[Fact]
152+
public void Should_Return_Zero_For_Aggregates_When_Source_Is_Null()
153+
{
154+
OrderEmailModel model = new OrderEmailModel
155+
{
156+
Customer = null
157+
};
158+
159+
string result = model.Map("{{ __sum(Customer.Payments.Amount) }}|{{ __avg(Customer.Payments.Amount) }}|{{ __count(Customer.Payments.Amount) }}|{{ __min(Customer.Payments.Amount) }}|{{ __max(Customer.Payments.Amount) }}");
160+
Assert.Equal("0|0|0|0|0", result);
161+
}
162+
163+
[Fact]
164+
public void Should_Return_Zero_When_Calc_Uses_Null_Operand_Path()
165+
{
166+
OrderEmailModel model = new OrderEmailModel
167+
{
168+
PaidAmount = 5000,
169+
Customer = null
170+
};
171+
172+
string result = model.Map("A{{ __calc(PaidAmount - Customer.CreditLimit) }}B");
173+
Assert.Equal("A0B", result);
174+
}
175+
176+
[Fact]
177+
public void Should_Support_Expressions_Without_Number_Format()
178+
{
179+
OrderEmailModel model = new OrderEmailModel
180+
{
181+
PaidAmount = 10000,
182+
Customer = new OrderCustomer
183+
{
184+
CreditLimit = 4500,
185+
Payments = new List<OrderPayment>
186+
{
187+
new OrderPayment { Amount = 1000 },
188+
new OrderPayment { Amount = 2000 },
189+
new OrderPayment { Amount = 1500 }
190+
}
191+
}
192+
};
193+
194+
string result = model.Map("{{ __sum(Customer.Payments.Amount) }}|{{ __calc(PaidAmount - Customer.CreditLimit) }}");
195+
Assert.Equal("4500|5500", result);
196+
}
197+
198+
[Fact]
199+
public void Should_Render_Empty_When_Sum_Path_Is_String_Based()
200+
{
201+
OrderEmailModel model = new OrderEmailModel
202+
{
203+
Items = new List<OrderLineItem>
204+
{
205+
new OrderLineItem { Name = "Keyboard" },
206+
new OrderLineItem { Name = "Mouse" }
207+
}
208+
};
209+
210+
string result = model.Map("X{{ __sum(Items.Name) }}Y");
211+
Assert.Equal("XY", result);
212+
}
213+
214+
[Fact]
215+
public void Should_Render_Empty_When_Sum_Path_Is_Date_Based()
216+
{
217+
OrderEmailModel model = new OrderEmailModel
218+
{
219+
OrderDate = new System.DateTime(2026, 03, 07)
220+
};
221+
222+
string result = model.Map("X{{ __sum(OrderDate) }}Y");
223+
Assert.Equal("XY", result);
224+
}
225+
}
226+
}

ObjectSemantics.NET.Tests/MoqModels/CustomerPayment.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,12 @@ public class Customer
2424
public string FirstName { get; set; }
2525
public string LastName { get; set; }
2626
public string CompanyName { get; set; }
27+
public CustomerBankingDetail BankingDetail { get; set; }
28+
}
29+
30+
public class CustomerBankingDetail
31+
{
32+
public string BankName { get; set; }
33+
public string AccountNumber { get; set; }
2734
}
2835
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace ObjectSemantics.NET.Tests.MoqModels
5+
{
6+
public class OrderEmailModel
7+
{
8+
public string OrderNo { get; set; }
9+
public DateTime OrderDate { get; set; }
10+
public decimal Subtotal { get; set; }
11+
public decimal Tax { get; set; }
12+
public decimal Total { get; set; }
13+
public decimal PaidAmount { get; set; }
14+
public bool IsPaid { get; set; }
15+
public OrderCustomer Customer { get; set; }
16+
public List<OrderLineItem> Items { get; set; } = new List<OrderLineItem>();
17+
}
18+
19+
public class OrderCustomer
20+
{
21+
public string FullName { get; set; }
22+
public string Email { get; set; }
23+
public decimal CreditLimit { get; set; }
24+
public List<OrderPayment> Payments { get; set; } = new List<OrderPayment>();
25+
public OrderAddress BillingAddress { get; set; }
26+
}
27+
28+
public class OrderAddress
29+
{
30+
public string Line1 { get; set; }
31+
public string City { get; set; }
32+
public string Country { get; set; }
33+
}
34+
35+
public class OrderLineItem
36+
{
37+
public string Name { get; set; }
38+
public int Quantity { get; set; }
39+
public decimal UnitPrice { get; set; }
40+
public decimal LineTotal { get; set; }
41+
}
42+
43+
public class OrderPayment
44+
{
45+
public decimal Amount { get; set; }
46+
public decimal PaidAmount { get; set; }
47+
}
48+
}

0 commit comments

Comments
 (0)