๐Ÿฆโ€โฌ› Snapshot testing in Gleam

:heavy_minus_sign: Drop the `glam` dependency

+4
CHANGELOG.md
··· 1 1 # Changelog 2 2 3 + ## v1.0.4 - 2024-02-01 4 + 5 + - โž– Drop the `glam` dependency 6 + 3 7 ## v1.0.3 - 2024-02-01 4 8 5 9 - ๐Ÿง‘๐Ÿปโ€๐Ÿ’ป Improve diffs look
+1 -1
birdie_snapshots/diffing_a_case_expression.accepted
··· 1 1 --- 2 - version: 1.0.2 2 + version: 1.0.3 3 3 title: diffing a case expression 4 4 --- 5 5 case foo(bar, baz) {
+1 -1
birdie_snapshots/my_favourite_number_wrapped_in_a_result.accepted
··· 1 1 --- 2 - version: 1.0.0 2 + version: 1.0.3 3 3 title: my favourite number wrapped in a result 4 4 --- 5 5 Ok(11)
+1 -1
birdie_snapshots/my_first_snapshot.accepted
··· 1 1 --- 2 - version: 1.0.0 2 + version: 1.0.3 3 3 title: my first snapshot 4 4 --- 5 5 ๐Ÿฆโ€โฌ› smile for the birdie!
+1 -1
birdie_snapshots/snapping_a_list_of_numbers.accepted
··· 1 1 --- 2 - version: 1.0.2 2 + version: 1.0.3 3 3 title: snapping a list of numbers 4 4 --- 5 5 [ 1, 2, 3, 4 ]
-1
gleam.toml
··· 13 13 filepath = "~> 0.1" 14 14 justin = "~> 1.0" 15 15 gleam_community_ansi = "~> 1.4" 16 - glam = "~> 1.3" 17 16 argv = "~> 1.0" 18 17 gleam_erlang = "~> 0.24" 19 18 rank = "~> 1.0"
+2 -4
manifest.toml
··· 4 4 packages = [ 5 5 { name = "argv", version = "1.0.1", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "A6E9009E50BBE863EB37D963E4315398D41A3D87D0075480FC244125808F964A" }, 6 6 { name = "filepath", version = "0.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "534E8161A0DE192A9A105EFEC34369E9FD5834BB58ED449B5ACAEE8704358588" }, 7 - { name = "gap", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_community_ansi"], otp_app = "gap", source = "hex", outer_checksum = "2EE1B0A17E85CF73A0C1D29DA315A2699117A8F549C8E8D89FA8261BE41EDEB1" }, 8 - { name = "glam", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glam", source = "hex", outer_checksum = "02E0311862B9669C3E8CE73FA5A95D8FA457C6ACB48D95FBE808ABFAE0A1CEB0" }, 9 - { name = "gleam_community_ansi", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_community_colour"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "FE79E08BF97009729259B6357EC058315B6FBB916FAD1C2FF9355115FEB0D3A4" }, 7 + { name = "gap", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_stdlib"], otp_app = "gap", source = "hex", outer_checksum = "2EE1B0A17E85CF73A0C1D29DA315A2699117A8F549C8E8D89FA8261BE41EDEB1" }, 8 + { name = "gleam_community_ansi", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "FE79E08BF97009729259B6357EC058315B6FBB916FAD1C2FF9355115FEB0D3A4" }, 10 9 { name = "gleam_community_colour", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "A49A5E3AE8B637A5ACBA80ECB9B1AFE89FD3D5351FF6410A42B84F666D40D7D5" }, 11 10 { name = "gleam_erlang", version = "0.24.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "26BDB52E61889F56A291CB34167315780EE4AA20961917314446542C90D1C1A0" }, 12 11 { name = "gleam_stdlib", version = "0.34.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "1FB8454D2991E9B4C0C804544D8A9AD0F6184725E20D63C3155F0AEB4230B016" }, ··· 20 19 argv = { version = "~> 1.0" } 21 20 filepath = { version = "~> 0.1" } 22 21 gap = { version = "~> 1.1" } 23 - glam = { version = "~> 1.3" } 24 22 gleam_community_ansi = { version = "~> 1.4" } 25 23 gleam_erlang = { version = "~> 0.24" } 26 24 gleam_stdlib = { version = "~> 0.34 or ~> 1.0" }
+62 -44
src/birdie.gleam
··· 10 10 import argv 11 11 import birdie/internal/diff.{type DiffLine, DiffLine} 12 12 import filepath 13 - import glam/doc 14 13 import gleeunit/should 15 14 import justin 16 15 import rank ··· 508 507 } 509 508 510 509 fn pretty_info_line(line: InfoLine, width: Int) -> String { 511 - let title_length = case line { 512 - InfoLineWithNoTitle(..) -> 2 513 - InfoLineWithTitle(title: title, ..) -> string.length(title) 510 + let prefix = case line { 511 + InfoLineWithNoTitle(..) -> " " 512 + InfoLineWithTitle(title: title, ..) -> " " <> title <> ": " 514 513 } 515 - 516 - let line_doc = case line.split { 517 - DoNotSplit -> doc.from_string(line.content) 514 + let prefix_length = string.length(prefix) 515 + case line.split { 516 + Truncate -> prefix <> truncate(line.content, width - prefix_length) 517 + DoNotSplit -> prefix <> line.content 518 518 SplitWords -> 519 - string.split(line.content, on: "\n") 520 - |> list.map(fn(line) { 521 - string.split(line, on: " ") 522 - |> list.map(doc.from_string) 523 - |> doc.join(with: doc.flex_space) 524 - }) 525 - |> doc.join(with: doc.line) 526 - |> doc.group 527 - |> doc.nest(by: title_length + 4) 528 - 529 - Truncate -> { 530 - let max_content_length = width - title_length - 6 531 - let content_length = string.length(line.content) 532 - case content_length > max_content_length { 533 - False -> doc.from_string(line.content) 534 - True -> 535 - string.to_graphemes(line.content) 536 - |> list.take(max_content_length - 3) 537 - |> string.join(with: "") 538 - |> string.append("...") 539 - |> doc.from_string 519 + case to_lines(line.content, width - prefix_length) { 520 + [] -> prefix 521 + [line, ..lines] -> { 522 + use acc, line <- list.fold(over: lines, from: prefix <> line) 523 + acc <> "\n" <> string.repeat(" ", prefix_length) <> line 524 + } 540 525 } 541 - } 542 526 } 543 - 544 - // This is an ugly hack that I need because `glam` currently doesn't take into 545 - // account color codes. 546 - // Those are invisible but still contribute to the length of a string, so I 547 - // have to artifically set the width to a higher limit to take into account 548 - // the length of the color codes added to the lines' titles. 549 - let ansi_code_len = 7 550 - 551 - case line { 552 - InfoLineWithNoTitle(..) -> doc.from_string(" ") 553 - InfoLineWithTitle(title: title, ..) -> 554 - doc.from_string(ansi.blue(" " <> title <> ": ")) 555 - } 556 - |> doc.append(line_doc) 557 - |> doc.to_string(width + ansi_code_len) 558 527 } 559 528 560 529 fn pretty_diff_line(diff_line: DiffLine, padding: Int) -> String { ··· 587 556 } 588 557 589 558 pretty_number <> separator <> pretty_line 559 + } 560 + 561 + // --- STRING UTILITIES -------------------------------------------------------- 562 + 563 + fn truncate(string: String, max_length: Int) -> String { 564 + case string.length(string) > max_length { 565 + False -> string 566 + True -> 567 + string.to_graphemes(string) 568 + |> list.take(max_length - 3) 569 + |> string.join(with: "") 570 + |> string.append("...") 571 + } 572 + } 573 + 574 + fn to_lines(string: String, max_length: Int) -> List(String) { 575 + // We still want to keep the original lines, so we work line by line. 576 + use line <- list.flat_map(string.split(string, on: "\n")) 577 + let words = string.split(line, on: " ") 578 + do_to_lines([], "", 0, words, max_length) 579 + } 580 + 581 + fn do_to_lines( 582 + lines: List(String), 583 + line: String, 584 + line_length: Int, 585 + words: List(String), 586 + max_length: Int, 587 + ) -> List(String) { 588 + case words { 589 + [] -> 590 + case line == "" { 591 + True -> list.reverse(lines) 592 + False -> list.reverse([line, ..lines]) 593 + } 594 + 595 + [word, ..rest] -> { 596 + let word_length = string.length(word) 597 + let new_line_length = word_length + line_length + 1 598 + // ^ With the +1 we account for the whitespace that separates words! 599 + case new_line_length > max_length { 600 + True -> do_to_lines([line, ..lines], "", 0, words, max_length) 601 + False -> { 602 + let new_line = line <> " " <> word 603 + do_to_lines(lines, new_line, new_line_length, rest, max_length) 604 + } 605 + } 606 + } 607 + } 590 608 } 591 609 592 610 // --- CLI COMMAND -------------------------------------------------------------