Skip to content

Commit 3443d81

Browse files
authored
Merge pull request #49 from goswinr/claude/add-comprehensive-tests-Nc20Y
Add comprehensive tests for edge cases and immutability
2 parents 7e50bb3 + 4bb5223 commit 3443d81

File tree

3 files changed

+1289
-31
lines changed

3 files changed

+1289
-31
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
## [0.24.2] - 2026-01-24
1111
### Fixed
1212
- minor internal optimizations
13+
### Added
14+
- more tests
1315

1416

1517
## [0.24.1] - 2026-01-17

Tests/Extensions.fs

Lines changed: 197 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,30 @@ module Extensions =
177177
Expect.equal xs.Second 6 "Expected Second to be changed to the new value"
178178

179179
//---- xs.Third ----
180-
// Similar tests can be written for Third
180+
testCase "Third getter raises exception on Array with less than 3 items" <| fun _ ->
181+
let xs = [| 1; 2|]
182+
let testCode = fun () -> xs.Third |> ignore
183+
Expect.throws testCode "Expected an IndexOutOfRangeException"
184+
185+
testCase "Third setter raises exception on Array with less than 3 items" <| fun _ ->
186+
let xs = [| 1; 2|]
187+
let testCode = fun () -> xs.Third <- 1
188+
Expect.throws testCode "Expected an IndexOutOfRangeException"
189+
190+
testCase "Third getter returns third item on Array with 3 or more items" <| fun _ ->
191+
let xs = [| 1; 2; 3; 4; 5|]
192+
let thirdItem = xs.Third
193+
Expect.equal thirdItem 3 "Expected Third to be equal to the third item in the Array"
194+
195+
testCase "Third setter changes third item on Array with 3 or more items" <| fun _ ->
196+
let xs = [| 1; 2; 3; 4; 5|]
197+
xs.Third <- 6
198+
Expect.equal xs.Third 6 "Expected Third to be changed to the new value"
199+
200+
testCase "Third getter on empty Array raises exception" <| fun _ ->
201+
let xs : int[] = [||]
202+
let testCode = fun () -> xs.Third |> ignore
203+
Expect.throws testCode "Expected an IndexOutOfRangeException"
181204

182205
//---- xs.IsEmpty ----
183206
testCase "IsEmpty returns true for empty Array" <| fun _ ->
@@ -265,4 +288,177 @@ module Extensions =
265288
let expected = "array<Int32> with 6 items:\n 0: 1\n 1: 2\n 2: 3\n ...\n 5: 6"
266289
Expect.equal s expected "toString entries"
267290

291+
//---- xs.FailIfEmpty ----
292+
testCase "FailIfEmpty returns array when not empty" <| fun _ ->
293+
let xs = [| 1; 2; 3|]
294+
let result = xs.FailIfEmpty("should not throw")
295+
Expect.equal xs result "Expected same array to be returned"
296+
297+
testCase "FailIfEmpty throws on empty Array" <| fun _ ->
298+
let xs : int[] = [||]
299+
let testCode = fun () -> xs.FailIfEmpty("is empty") |> ignore
300+
Expect.throws testCode "Expected an Exception on empty array"
301+
302+
//---- xs.FailIfLessThan ----
303+
testCase "FailIfLessThan returns array when count is sufficient" <| fun _ ->
304+
let xs = [| 1; 2; 3|]
305+
let result = xs.FailIfLessThan(3, "should not throw")
306+
Expect.equal xs result "Expected same array to be returned"
307+
308+
testCase "FailIfLessThan throws when count is insufficient" <| fun _ ->
309+
let xs = [| 1; 2|]
310+
let testCode = fun () -> xs.FailIfLessThan(3, "too few") |> ignore
311+
Expect.throws testCode "Expected an Exception when array has too few items"
312+
313+
testCase "FailIfLessThan returns array when count exceeds minimum" <| fun _ ->
314+
let xs = [| 1; 2; 3; 4; 5|]
315+
let result = xs.FailIfLessThan(3, "should not throw")
316+
Expect.equal xs result "Expected same array to be returned"
317+
318+
//---- xs.HasItems ----
319+
testCase "HasItems returns true for non-empty Array" <| fun _ ->
320+
let xs = [| 1; 2; 3|]
321+
Expect.isTrue xs.HasItems "Expected HasItems to be true for a non-empty Array"
322+
323+
testCase "HasItems returns false for empty Array" <| fun _ ->
324+
let xs : int[] = [||]
325+
Expect.isFalse xs.HasItems "Expected HasItems to be false for an empty Array"
326+
327+
//---- Immutability tests for extension members ----
328+
testCase "Get does not modify input array" <| fun _ ->
329+
let xs = [| 1; 2; 3|]
330+
let original = xs.Duplicate()
331+
let _ = xs.Get 1
332+
Expect.isTrue (xs = original) "Get should not modify input array"
333+
334+
testCase "GetNeg does not modify input array" <| fun _ ->
335+
let xs = [| 1; 2; 3|]
336+
let original = xs.Duplicate()
337+
let _ = xs.GetNeg -1
338+
Expect.isTrue (xs = original) "GetNeg should not modify input array"
339+
340+
testCase "GetLooped does not modify input array" <| fun _ ->
341+
let xs = [| 1; 2; 3|]
342+
let original = xs.Duplicate()
343+
let _ = xs.GetLooped 5
344+
Expect.isTrue (xs = original) "GetLooped should not modify input array"
345+
346+
testCase "Duplicate creates independent copy" <| fun _ ->
347+
let xs = [| 1; 2; 3|]
348+
let dup = xs.Duplicate()
349+
dup.[0] <- 99
350+
Expect.equal xs.[0] 1 "Original array should not be modified when duplicate is changed"
351+
352+
testCase "Slice does not modify input array" <| fun _ ->
353+
let xs = [| 1; 2; 3; 4; 5|]
354+
let original = xs.Duplicate()
355+
let _ = xs.Slice(1, 3)
356+
Expect.isTrue (xs = original) "Slice should not modify input array"
357+
358+
testCase "First getter does not modify input array" <| fun _ ->
359+
let xs = [| 1; 2; 3|]
360+
let original = xs.Duplicate()
361+
let _ = xs.First
362+
Expect.isTrue (xs = original) "First getter should not modify input array"
363+
364+
testCase "Last getter does not modify input array" <| fun _ ->
365+
let xs = [| 1; 2; 3|]
366+
let original = xs.Duplicate()
367+
let _ = xs.Last
368+
Expect.isTrue (xs = original) "Last getter should not modify input array"
369+
370+
//---- Additional edge cases ----
371+
testCase "DebugIndexer throws on negative index" <| fun _ ->
372+
let xs = [| 1; 2; 3|]
373+
let testCode = fun () -> xs.DebugIdx.[-1] |> ignore
374+
Expect.throws testCode "Expected an IndexOutOfRangeException"
375+
376+
testCase "Idx gets item at index" <| fun _ ->
377+
let xs = [| 1; 2; 3|]
378+
Expect.equal (xs.Idx 1) 2 "Idx should return the item at index"
379+
380+
testCase "Idx throws on invalid index" <| fun _ ->
381+
let xs = [| 1; 2; 3|]
382+
let testCode = fun () -> xs.Idx 3 |> ignore
383+
Expect.throws testCode "Expected an IndexOutOfRangeException"
384+
385+
testCase "GetNeg with boundary negative index" <| fun _ ->
386+
let xs = [| 1; 2; 3|]
387+
Expect.equal (xs.GetNeg -3) 1 "GetNeg -3 should return first item"
388+
389+
testCase "GetNeg throws when negative index is too large" <| fun _ ->
390+
let xs = [| 1; 2; 3|]
391+
let testCode = fun () -> xs.GetNeg -4 |> ignore
392+
Expect.throws testCode "Expected an IndexOutOfRangeException"
393+
394+
testCase "SetNeg with boundary negative index" <| fun _ ->
395+
let xs = [| 1; 2; 3|]
396+
xs.SetNeg -3 99
397+
Expect.equal xs.[0] 99 "SetNeg -3 should set first item"
398+
399+
testCase "SetNeg throws when negative index is too large" <| fun _ ->
400+
let xs = [| 1; 2; 3|]
401+
let testCode = fun () -> xs.SetNeg -4 99
402+
Expect.throws testCode "Expected an IndexOutOfRangeException"
403+
404+
testCase "GetLooped with large positive index" <| fun _ ->
405+
let xs = [| 1; 2; 3|]
406+
Expect.equal (xs.GetLooped 100) (xs.[100 % 3]) "GetLooped should wrap large positive index"
407+
408+
testCase "GetLooped with large negative index" <| fun _ ->
409+
let xs = [| 1; 2; 3|]
410+
let expected = xs.[((-100 % 3) + 3) % 3]
411+
Expect.equal (xs.GetLooped -100) expected "GetLooped should wrap large negative index"
412+
413+
testCase "SetLooped with large positive index" <| fun _ ->
414+
let xs = [| 1; 2; 3|]
415+
xs.SetLooped 100 99
416+
Expect.equal xs.[100 % 3] 99 "SetLooped should wrap large positive index"
417+
418+
testCase "Slice with negative start and positive end" <| fun _ ->
419+
let xs = [| 1; 2; 3; 4; 5|]
420+
let result = xs.Slice(-3, 4)
421+
Expect.isTrue (result = [|3; 4; 5|]) "Slice should work with mixed indices"
422+
423+
testCase "Slice throws when start is after end" <| fun _ ->
424+
let xs = [| 1; 2; 3; 4; 5|]
425+
let testCode = fun () -> xs.Slice(3, 1) |> ignore
426+
Expect.throws testCode "Expected an IndexOutOfRangeException"
427+
428+
testCase "Slice throws when indices are out of bounds" <| fun _ ->
429+
let xs = [| 1; 2; 3|]
430+
let testCode1 = fun () -> xs.Slice(5, 6) |> ignore
431+
let testCode2 = fun () -> xs.Slice(0, 5) |> ignore
432+
Expect.throws testCode1 "Expected an IndexOutOfRangeException for start out of bounds"
433+
Expect.throws testCode2 "Expected an IndexOutOfRangeException for end out of bounds"
434+
435+
testCase "IsSingleton returns false for empty Array" <| fun _ ->
436+
let xs : int[] = [||]
437+
Expect.isFalse xs.IsSingleton "Expected IsSingleton to be false for an empty Array"
438+
439+
testCase "LastIndex returns correct value for various arrays" <| fun _ ->
440+
Expect.equal [|1|].LastIndex 0 "Single item array should have LastIndex 0"
441+
Expect.equal [|1;2;3|].LastIndex 2 "Three item array should have LastIndex 2"
442+
443+
testCase "FirstAndOnly fails on empty Array" <| fun _ ->
444+
let xs : int[] = [||]
445+
let testCode = fun () -> xs.FirstAndOnly |> ignore
446+
Expect.throws testCode "Expected an IndexOutOfRangeException"
447+
448+
testCase "SecondLast on two item Array" <| fun _ ->
449+
let xs = [| 1; 2|]
450+
Expect.equal xs.SecondLast 1 "SecondLast on two item array should return first item"
451+
452+
testCase "ThirdLast on three item Array" <| fun _ ->
453+
let xs = [| 1; 2; 3|]
454+
Expect.equal xs.ThirdLast 1 "ThirdLast on three item array should return first item"
455+
456+
testCase "Second on two item Array" <| fun _ ->
457+
let xs = [| 1; 2|]
458+
Expect.equal xs.Second 2 "Second on two item array should return second item"
459+
460+
testCase "Third on three item Array" <| fun _ ->
461+
let xs = [| 1; 2; 3|]
462+
Expect.equal xs.Third 3 "Third on three item array should return third item"
463+
268464
]

0 commit comments

Comments
 (0)