test_core_compress.odin 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. package test_core_compress
  2. /*
  3. Copyright 2021 Jeroen van Rijn <[email protected]>.
  4. Made available under Odin's BSD-3 license.
  5. List of contributors:
  6. Jeroen van Rijn: Initial implementation.
  7. A test suite for ZLIB, GZIP and Shoco.
  8. */
  9. import "core:testing"
  10. import "core:compress/zlib"
  11. import "core:compress/gzip"
  12. import "core:compress/shoco"
  13. import "core:bytes"
  14. import "core:fmt"
  15. import "core:mem"
  16. import "core:os"
  17. import "core:io"
  18. TEST_count := 0
  19. TEST_fail := 0
  20. when ODIN_TEST {
  21. expect :: testing.expect
  22. log :: testing.log
  23. } else {
  24. expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
  25. TEST_count += 1
  26. if !condition {
  27. TEST_fail += 1
  28. fmt.printf("[%v] %v\n", loc, message)
  29. return
  30. }
  31. }
  32. log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
  33. fmt.printf("[%v] ", loc)
  34. fmt.printf("log: %v\n", v)
  35. }
  36. }
  37. main :: proc() {
  38. w := io.to_writer(os.stream_from_handle(os.stdout))
  39. t := testing.T{w=w}
  40. zlib_test(&t)
  41. gzip_test(&t)
  42. shoco_test(&t)
  43. fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
  44. if TEST_fail > 0 {
  45. os.exit(1)
  46. }
  47. }
  48. @test
  49. zlib_test :: proc(t: ^testing.T) {
  50. ODIN_DEMO := []u8{
  51. 120, 156, 101, 144, 77, 110, 131, 48, 16, 133, 215, 204, 41, 158, 44,
  52. 69, 73, 32, 148, 182, 75, 35, 14, 208, 125, 47, 96, 185, 195, 143,
  53. 130, 13, 50, 38, 81, 84, 101, 213, 75, 116, 215, 43, 246, 8, 53,
  54. 82, 126, 8, 181, 188, 152, 153, 111, 222, 147, 159, 123, 165, 247, 170,
  55. 98, 24, 213, 88, 162, 198, 244, 157, 243, 16, 186, 115, 44, 75, 227,
  56. 5, 77, 115, 72, 137, 222, 117, 122, 179, 197, 39, 69, 161, 170, 156,
  57. 50, 144, 5, 68, 130, 4, 49, 126, 127, 190, 191, 144, 34, 19, 57,
  58. 69, 74, 235, 209, 140, 173, 242, 157, 155, 54, 158, 115, 162, 168, 12,
  59. 181, 239, 246, 108, 17, 188, 174, 242, 224, 20, 13, 199, 198, 235, 250,
  60. 194, 166, 129, 86, 3, 99, 157, 172, 37, 230, 62, 73, 129, 151, 252,
  61. 70, 211, 5, 77, 31, 104, 188, 160, 113, 129, 215, 59, 205, 22, 52,
  62. 123, 160, 83, 142, 255, 242, 89, 123, 93, 149, 200, 50, 188, 85, 54,
  63. 252, 18, 248, 192, 238, 228, 235, 198, 86, 224, 118, 224, 176, 113, 166,
  64. 112, 67, 106, 227, 159, 122, 215, 88, 95, 110, 196, 123, 205, 183, 224,
  65. 98, 53, 8, 104, 213, 234, 201, 147, 7, 248, 192, 14, 170, 29, 25,
  66. 171, 15, 18, 59, 138, 112, 63, 23, 205, 110, 254, 136, 109, 78, 231,
  67. 63, 234, 138, 133, 204,
  68. }
  69. buf: bytes.Buffer
  70. track: mem.Tracking_Allocator
  71. mem.tracking_allocator_init(&track, context.allocator)
  72. context.allocator = mem.tracking_allocator(&track)
  73. err := zlib.inflate(ODIN_DEMO, &buf)
  74. expect(t, err == nil, "ZLIB failed to decompress ODIN_DEMO")
  75. s := bytes.buffer_to_string(&buf)
  76. expect(t, s[68] == 240 && s[69] == 159 && s[70] == 152, "ZLIB result should've contained 😃 at position 68.")
  77. expect(t, len(s) == 438, "ZLIB result has an unexpected length.")
  78. bytes.buffer_destroy(&buf)
  79. for _, v in track.allocation_map {
  80. error := fmt.tprintf("ZLIB test leaked %v bytes", v.size)
  81. expect(t, false, error)
  82. }
  83. }
  84. @test
  85. gzip_test :: proc(t: ^testing.T) {
  86. // Small GZIP file with fextra, fname and fcomment present.
  87. TEST: []u8 = {
  88. 0x1f, 0x8b, 0x08, 0x1c, 0xcb, 0x3b, 0x3a, 0x5a,
  89. 0x02, 0x03, 0x07, 0x00, 0x61, 0x62, 0x03, 0x00,
  90. 0x63, 0x64, 0x65, 0x66, 0x69, 0x6c, 0x65, 0x6e,
  91. 0x61, 0x6d, 0x65, 0x00, 0x54, 0x68, 0x69, 0x73,
  92. 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x63, 0x6f,
  93. 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x2b, 0x48,
  94. 0xac, 0xcc, 0xc9, 0x4f, 0x4c, 0x01, 0x00, 0x15,
  95. 0x6a, 0x2c, 0x42, 0x07, 0x00, 0x00, 0x00,
  96. }
  97. buf: bytes.Buffer
  98. track: mem.Tracking_Allocator
  99. mem.tracking_allocator_init(&track, context.allocator)
  100. context.allocator = mem.tracking_allocator(&track)
  101. err := gzip.load(TEST, &buf) // , 438);
  102. expect(t, err == nil, "GZIP failed to decompress TEST")
  103. s := bytes.buffer_to_string(&buf)
  104. expect(t, s == "payload", "GZIP result wasn't 'payload'")
  105. bytes.buffer_destroy(&buf)
  106. for _, v in track.allocation_map {
  107. error := fmt.tprintf("GZIP test leaked %v bytes", v.size)
  108. expect(t, false, error)
  109. }
  110. }
  111. @test
  112. shoco_test :: proc(t: ^testing.T) {
  113. Shoco_Tests :: []struct{
  114. compressed: []u8,
  115. raw: []u8,
  116. short_pack: int,
  117. short_sentinel: int,
  118. }{
  119. { #load("../assets/Shoco/README.md.shoco"), #load("../assets/Shoco/README.md"), 10, 1006 },
  120. { #load("../assets/Shoco/LICENSE.shoco"), #load("../assets/Shoco/LICENSE"), 25, 68 },
  121. }
  122. for v in Shoco_Tests {
  123. when ODIN_OS == .Windows {
  124. v := v
  125. // Compressed source files are not encoded with carriage returns but git replaces raw files lf with crlf on commit (on windows only)
  126. // So replace crlf with lf on windows
  127. v.raw, _ = bytes.replace_all(v.raw, { 0xD, 0xA }, { 0xA })
  128. }
  129. expected_raw := len(v.raw)
  130. expected_compressed := len(v.compressed)
  131. biggest_unpacked := shoco.decompress_bound(expected_compressed)
  132. biggest_packed := shoco.compress_bound(expected_raw)
  133. buffer := make([]u8, max(biggest_packed, biggest_unpacked))
  134. defer delete(buffer)
  135. size, err := shoco.decompress(v.compressed, buffer[:])
  136. msg := fmt.tprintf("Expected `decompress` to return `nil`, got %v", err)
  137. expect(t, err == nil, msg)
  138. msg = fmt.tprintf("Decompressed %v bytes into %v. Expected to decompress into %v bytes.", len(v.compressed), size, expected_raw)
  139. expect(t, size == expected_raw, msg)
  140. expect(t, string(buffer[:size]) == string(v.raw), "Decompressed contents don't match.")
  141. size, err = shoco.compress(string(v.raw), buffer[:])
  142. expect(t, err == nil, "Expected `compress` to return `nil`.")
  143. msg = fmt.tprintf("Compressed %v bytes into %v. Expected to compress into %v bytes.", expected_raw, size, expected_compressed)
  144. expect(t, size == expected_compressed, msg)
  145. size, err = shoco.decompress(v.compressed, buffer[:expected_raw - 10])
  146. msg = fmt.tprintf("Decompressing into too small a buffer returned %v, expected `.Output_Too_Short`", err)
  147. expect(t, err == .Output_Too_Short, msg)
  148. size, err = shoco.compress(string(v.raw), buffer[:expected_compressed - 10])
  149. msg = fmt.tprintf("Compressing into too small a buffer returned %v, expected `.Output_Too_Short`", err)
  150. expect(t, err == .Output_Too_Short, msg)
  151. size, err = shoco.decompress(v.compressed[:v.short_pack], buffer[:])
  152. expect(t, err == .Stream_Too_Short, "Expected `decompress` to return `Stream_Too_Short` because there was no more data after selecting a pack.")
  153. size, err = shoco.decompress(v.compressed[:v.short_sentinel], buffer[:])
  154. expect(t, err == .Stream_Too_Short, "Expected `decompress` to return `Stream_Too_Short` because there was no more data after non-ASCII sentinel.")
  155. }
  156. }