-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathunit_system_conversion_test.go
More file actions
236 lines (194 loc) · 7.49 KB
/
unit_system_conversion_test.go
File metadata and controls
236 lines (194 loc) · 7.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
package cooklang
import (
"testing"
)
func TestNewIngredient(t *testing.T) {
// Test that NewIngredient creates an ingredient with proper TypedUnit
tests := []struct {
name string
quantity float32
unit string
targetSystem UnitSystem
expectConv bool // Whether conversion should happen
}{
{"vodka", 50, "ml", UnitSystemUS, true},
{"sugar", 100, "g", UnitSystemUS, true},
{"lime juice", 1, "oz", UnitSystemMetric, true},
{"water", 2, "cups", UnitSystemMetric, true},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
// Create ingredient using NewIngredient constructor
ing := NewIngredient(tc.name, tc.quantity, tc.unit)
// Verify TypedUnit is set
if ing.TypedUnit == nil {
t.Errorf("NewIngredient(%s, %v, %s): TypedUnit should not be nil", tc.name, tc.quantity, tc.unit)
}
// Test that conversion works
converted := ing.ConvertToSystem(tc.targetSystem)
if tc.expectConv {
// Conversion should change the unit
if converted.Unit == ing.Unit && converted.Quantity == ing.Quantity {
t.Logf("Warning: No conversion happened for %s %v %s -> %s (might be expected for some units)",
tc.name, tc.quantity, tc.unit, tc.targetSystem)
} else {
t.Logf("%s: %.1f %s -> %.2f %s", tc.name, tc.quantity, tc.unit, converted.Quantity, converted.Unit)
}
}
})
}
}
func TestNewIngredientVsManualCreation(t *testing.T) {
// Test that NewIngredient produces different results than manual struct creation
// when it comes to unit conversion
// Create ingredient manually (without TypedUnit)
manualIng := &Ingredient{
Name: "vodka",
Quantity: 50,
Unit: "ml",
}
// Create ingredient using NewIngredient
constructedIng := NewIngredient("vodka", 50, "ml")
// Try to convert both
manualConverted := manualIng.ConvertToSystem(UnitSystemUS)
constructedConverted := constructedIng.ConvertToSystem(UnitSystemUS)
t.Logf("Manual creation: %.1f %s -> %.2f %s",
manualIng.Quantity, manualIng.Unit,
manualConverted.Quantity, manualConverted.Unit)
t.Logf("NewIngredient: %.1f %s -> %.2f %s",
constructedIng.Quantity, constructedIng.Unit,
constructedConverted.Quantity, constructedConverted.Unit)
// The manually created ingredient should NOT convert (TypedUnit is nil)
if manualConverted.Unit != manualIng.Unit {
t.Errorf("Manual ingredient should not convert without TypedUnit")
}
// The NewIngredient-created ingredient SHOULD convert
if constructedConverted.Unit == constructedIng.Unit && constructedConverted.Quantity == constructedIng.Quantity {
t.Errorf("NewIngredient should enable conversion, but no conversion happened")
}
}
func TestUnitSystemConversion(t *testing.T) {
// Create a test recipe with metric ingredients
testRecipe := `---
title: Test Recipe
servings: 4
---
Mix @flour{500%g} with @milk{250%ml} and @sugar{50%g}.
Add @butter{125%g} and @vanilla extract{5%ml}.
`
recipe, err := ParseString(testRecipe)
if err != nil {
t.Fatalf("Failed to parse recipe: %v", err)
}
// Test converting to US system
usShoppingList, err := recipe.GetShoppingListInSystem(UnitSystemUS)
if err != nil {
t.Fatalf("Failed to convert to US system: %v", err)
}
t.Logf("US Shopping List: %+v", usShoppingList)
// Test converting to Imperial system
imperialShoppingList, err := recipe.GetShoppingListInSystem(UnitSystemImperial)
if err != nil {
t.Fatalf("Failed to convert to Imperial system: %v", err)
}
t.Logf("Imperial Shopping List: %+v", imperialShoppingList)
// Test individual ingredient conversion
ingredients := recipe.GetIngredients()
for _, ingredient := range ingredients.Ingredients {
if ingredient.Unit != "" && ingredient.Quantity > 0 {
// Test conversion to US units
usIngredient := ingredient.ConvertToSystem(UnitSystemUS)
t.Logf("Original: %s %.1f%s -> US: %s %.1f%s",
ingredient.Name, ingredient.Quantity, ingredient.Unit,
usIngredient.Name, usIngredient.Quantity, usIngredient.Unit)
// Test conversion to Imperial units
imperialIngredient := ingredient.ConvertToSystem(UnitSystemImperial)
t.Logf("Original: %s %.1f%s -> Imperial: %s %.1f%s",
ingredient.Name, ingredient.Quantity, ingredient.Unit,
imperialIngredient.Name, imperialIngredient.Quantity, imperialIngredient.Unit)
}
}
}
func TestIngredientListConversion(t *testing.T) {
// Create test ingredients
ingredients := NewIngredientList()
// Add some metric ingredients
flour := &Ingredient{Name: "flour", Quantity: 1000, Unit: "g", TypedUnit: CreateTypedUnit("g")}
milk := &Ingredient{Name: "milk", Quantity: 500, Unit: "ml", TypedUnit: CreateTypedUnit("ml")}
sugar := &Ingredient{Name: "sugar", Quantity: 200, Unit: "g", TypedUnit: CreateTypedUnit("g")}
ingredients.Add(flour)
ingredients.Add(milk)
ingredients.Add(sugar)
// Convert to US system
usIngredients := ingredients.ConvertToSystem(UnitSystemUS)
t.Log("Original ingredients (metric):")
for _, ing := range ingredients.Ingredients {
t.Logf(" %s: %.1f %s", ing.Name, ing.Quantity, ing.Unit)
}
t.Log("Converted to US system:")
for _, ing := range usIngredients.Ingredients {
t.Logf(" %s: %.1f %s", ing.Name, ing.Quantity, ing.Unit)
}
// Convert to Imperial system
imperialIngredients := ingredients.ConvertToSystem(UnitSystemImperial)
t.Log("Converted to Imperial system:")
for _, ing := range imperialIngredients.Ingredients {
t.Logf(" %s: %.1f %s", ing.Name, ing.Quantity, ing.Unit)
}
}
func TestSmartUnitSelection(t *testing.T) {
// Test that large volumes get converted to appropriate units
testCases := []struct {
name string
quantity float32
unit string
system UnitSystem
expected string
}{
{"Large volume to US quarts", 2000, "ml", UnitSystemUS, "qt"},
{"Medium volume to US cups", 500, "ml", UnitSystemUS, "cup"},
{"Small volume to US tablespoons", 30, "ml", UnitSystemUS, "tbsp"},
{"Tiny volume to US teaspoons", 5, "ml", UnitSystemUS, "tsp"},
{"Large mass to kg", 2000, "g", UnitSystemMetric, "kg"},
{"Small mass stays as g", 500, "g", UnitSystemMetric, "g"},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
ingredient := &Ingredient{
Name: "test",
Quantity: tc.quantity,
Unit: tc.unit,
TypedUnit: CreateTypedUnit(tc.unit),
}
converted := ingredient.ConvertToSystem(tc.system)
if converted.Unit != tc.expected {
t.Errorf("Expected unit %s, got %s (quantity: %.1f)",
tc.expected, converted.Unit, converted.Quantity)
}
t.Logf("%.1f %s -> %.2f %s", tc.quantity, tc.unit, converted.Quantity, converted.Unit)
})
}
}
func TestConversionWithConsolidation(t *testing.T) {
// Create ingredients with same name but different units
ingredients := NewIngredientList()
// Add the same ingredient in different units
flour1 := &Ingredient{Name: "flour", Quantity: 500, Unit: "g", TypedUnit: CreateTypedUnit("g")}
flour2 := &Ingredient{Name: "flour", Quantity: 250, Unit: "g", TypedUnit: CreateTypedUnit("g")}
ingredients.Add(flour1)
ingredients.Add(flour2)
// Convert to US and consolidate
consolidated, err := ingredients.ConvertToSystemWithConsolidation(UnitSystemUS)
if err != nil {
t.Fatalf("Failed to convert and consolidate: %v", err)
}
if len(consolidated.Ingredients) != 1 {
t.Errorf("Expected 1 consolidated ingredient, got %d", len(consolidated.Ingredients))
}
flour := consolidated.Ingredients[0]
t.Logf("Consolidated flour: %.2f %s", flour.Quantity, flour.Unit)
// Should be approximately 1.65 lbs or similar US weight unit
if flour.Name != "flour" {
t.Errorf("Expected ingredient name 'flour', got '%s'", flour.Name)
}
}