[DEPRECATED] Go implementation of plcbundle
1package types_test
2
3import (
4 "bytes"
5 "fmt"
6 "testing"
7
8 "tangled.org/atscan.net/plcbundle/internal/types"
9)
10
11// ====================================================================================
12// CONSTANT VALIDATION TESTS
13// ====================================================================================
14
15func TestConstants(t *testing.T) {
16 t.Run("BundleSize", func(t *testing.T) {
17 if types.BUNDLE_SIZE != 10000 {
18 t.Errorf("BUNDLE_SIZE = %d, want 10000", types.BUNDLE_SIZE)
19 }
20
21 // Ensure it's a reasonable size
22 if types.BUNDLE_SIZE < 1000 {
23 t.Error("BUNDLE_SIZE too small")
24 }
25
26 if types.BUNDLE_SIZE > 100000 {
27 t.Error("BUNDLE_SIZE too large")
28 }
29 })
30
31 t.Run("IndexFile", func(t *testing.T) {
32 if types.INDEX_FILE != "plc_bundles.json" {
33 t.Errorf("INDEX_FILE = %s, want plc_bundles.json", types.INDEX_FILE)
34 }
35
36 // Should be a valid filename
37 if types.INDEX_FILE == "" {
38 t.Error("INDEX_FILE should not be empty")
39 }
40
41 // Should have .json extension
42 if len(types.INDEX_FILE) < 5 || types.INDEX_FILE[len(types.INDEX_FILE)-5:] != ".json" {
43 t.Error("INDEX_FILE should have .json extension")
44 }
45 })
46
47 t.Run("IndexVersion", func(t *testing.T) {
48 if types.INDEX_VERSION != "1.0" {
49 t.Errorf("INDEX_VERSION = %s, want 1.0", types.INDEX_VERSION)
50 }
51
52 // Should follow semantic versioning format (at least major.minor)
53 if len(types.INDEX_VERSION) < 3 {
54 t.Error("INDEX_VERSION should follow semantic versioning")
55 }
56 })
57}
58
59// ====================================================================================
60// LOGGER INTERFACE COMPLIANCE TESTS
61// ====================================================================================
62
63func TestLoggerInterface(t *testing.T) {
64 t.Run("MockLoggerImplementsInterface", func(t *testing.T) {
65 var logger types.Logger = &mockLogger{}
66
67 // Should compile and not panic
68 logger.Printf("test %s", "message")
69 logger.Println("test", "message")
70 })
71
72 t.Run("BufferedLoggerImplementation", func(t *testing.T) {
73 buf := &bytes.Buffer{}
74 logger := &bufferedLogger{buf: buf}
75
76 // Cast to interface
77 var _ types.Logger = logger
78
79 logger.Printf("formatted %s %d", "message", 42)
80 logger.Println("plain", "message")
81
82 output := buf.String()
83
84 if !containsString(output, "formatted message 42") {
85 t.Error("Printf output not captured")
86 }
87
88 if !containsString(output, "plain message") {
89 t.Error("Println output not captured")
90 }
91 })
92
93 t.Run("NullLoggerImplementation", func(t *testing.T) {
94 // Logger that discards all output
95 logger := &nullLogger{}
96
97 // Should not panic
98 var _ types.Logger = logger
99 logger.Printf("test %s", "ignored")
100 logger.Println("also", "ignored")
101 })
102
103 t.Run("MultiLoggerImplementation", func(t *testing.T) {
104 // Logger that writes to multiple destinations
105 buf1 := &bytes.Buffer{}
106 buf2 := &bytes.Buffer{}
107
108 logger := &multiLogger{
109 loggers: []types.Logger{
110 &bufferedLogger{buf: buf1},
111 &bufferedLogger{buf: buf2},
112 },
113 }
114
115 var _ types.Logger = logger
116
117 logger.Printf("test %s", "message")
118
119 // Both buffers should have the message
120 if !containsString(buf1.String(), "test message") {
121 t.Error("first logger didn't receive message")
122 }
123
124 if !containsString(buf2.String(), "test message") {
125 t.Error("second logger didn't receive message")
126 }
127 })
128}
129
130// ====================================================================================
131// CONSTANT USAGE IN CALCULATIONS
132// ====================================================================================
133
134func TestConstantUsage(t *testing.T) {
135 t.Run("GlobalPositionCalculation", func(t *testing.T) {
136 // Global position = bundleNumber * BUNDLE_SIZE + position
137 bundleNumber := 42
138 position := 1337
139
140 globalPos := bundleNumber*types.BUNDLE_SIZE + position
141 expected := 420000 + 1337
142
143 if globalPos != expected {
144 t.Errorf("global position calculation incorrect: got %d, want %d", globalPos, expected)
145 }
146 })
147
148 t.Run("BundleFromGlobalPosition", func(t *testing.T) {
149 globalPos := 88410345
150
151 bundleNumber := globalPos / types.BUNDLE_SIZE
152 position := globalPos % types.BUNDLE_SIZE
153
154 if bundleNumber != 8841 {
155 t.Errorf("bundle calculation wrong: got %d, want 8841", bundleNumber)
156 }
157
158 if position != 345 {
159 t.Errorf("position calculation wrong: got %d, want 345", position)
160 }
161 })
162
163 t.Run("OperationCountPerBundle", func(t *testing.T) {
164 // Each bundle should have exactly BUNDLE_SIZE operations
165 bundleCount := 100
166 totalOps := bundleCount * types.BUNDLE_SIZE
167
168 if totalOps != 1000000 {
169 t.Errorf("total ops calculation: got %d, want 1000000", totalOps)
170 }
171 })
172}
173
174// ====================================================================================
175// HELPER IMPLEMENTATIONS
176// ====================================================================================
177
178type mockLogger struct{}
179
180func (l *mockLogger) Printf(format string, v ...interface{}) {}
181func (l *mockLogger) Println(v ...interface{}) {}
182
183type bufferedLogger struct {
184 buf *bytes.Buffer
185}
186
187func (l *bufferedLogger) Printf(format string, v ...interface{}) {
188 fmt.Fprintf(l.buf, format+"\n", v...)
189}
190
191func (l *bufferedLogger) Println(v ...interface{}) {
192 fmt.Fprintln(l.buf, v...)
193}
194
195type nullLogger struct{}
196
197func (l *nullLogger) Printf(format string, v ...interface{}) {}
198func (l *nullLogger) Println(v ...interface{}) {}
199
200type multiLogger struct {
201 loggers []types.Logger
202}
203
204func (l *multiLogger) Printf(format string, v ...interface{}) {
205 for _, logger := range l.loggers {
206 logger.Printf(format, v...)
207 }
208}
209
210func (l *multiLogger) Println(v ...interface{}) {
211 for _, logger := range l.loggers {
212 logger.Println(v...)
213 }
214}
215
216func containsString(haystack, needle string) bool {
217 return bytes.Contains([]byte(haystack), []byte(needle))
218}