Runtime assertions for Ruby literal.fun
ruby
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 188 lines 4.9 kB view raw
1# frozen_string_literal: true 2 3include Literal::Types 4 5test "result block returns a checked result" do 6 result = Literal::Result(Integer, Symbol) do |type| 7 type.success(42) 8 end 9 10 assert Literal::Success === result 11 assert_equal 42, result.value! 12end 13 14test "result block requires throwing a result" do 15 error = assert_raises(Literal::ArgumentError) do 16 Literal::Result(Integer, Symbol) do 17 42 18 end 19 end 20 21 assert_equal "Expected block to throw a success or failure result", error.message 22end 23 24test "result block must throw, not return, a result" do 25 error = assert_raises(Literal::ArgumentError) do 26 Literal::Result(Integer, Symbol) do 27 Literal::Result(String, Symbol) { |type| type.success("42") } 28 end 29 end 30 31 assert_equal "Expected block to throw a success or failure result", error.message 32end 33 34test "and_then adopts returned success type" do 35 result = Literal::Result(Integer, Symbol) { |type| type.success(42) } 36 .and_then { |value| Literal::Result(String, RuntimeError) { |type| type.success(value.to_s) } } 37 38 assert result.success? 39 assert_equal "42", result.value! 40 assert Literal::Result(String, _Union(Symbol, RuntimeError)) === result 41end 42 43test "and_then unions failure types" do 44 result = Literal::Result(Integer, Symbol) { |type| type.success(42) } 45 .and_then { Literal::Result(String, RuntimeError) { |type| type.failure(RuntimeError.new("boom")) } } 46 47 assert result.failure? 48 assert RuntimeError === result.error! 49 assert Literal::Result(String, _Union(Symbol, RuntimeError)) === result 50end 51 52test "failure and_then does not yield" do 53 original = Literal::Result(Integer, Symbol) { |type| type.failure(:nope) } 54 yielded = false 55 56 result = original.and_then do 57 yielded = true 58 Literal::Result(String, RuntimeError) { |type| type.success("ok") } 59 end 60 61 refute yielded 62 assert result.equal?(original) 63end 64 65test "also yields success value and returns self" do 66 original = Literal::Result(Integer, Symbol) { |type| type.success(42) } 67 yielded = nil 68 69 result = original.also do |value| 70 yielded = value 71 end 72 73 assert_equal 42, yielded 74 assert result.equal?(original) 75end 76 77test "failure also does not yield" do 78 original = Literal::Result(Integer, Symbol) { |type| type.failure(:nope) } 79 yielded = false 80 81 result = original.also do 82 yielded = true 83 end 84 85 refute yielded 86 assert result.equal?(original) 87end 88 89test "and_then block must return result" do 90 result = Literal::Result(Integer, Symbol) { |type| type.success(42) } 91 92 error = assert_raises(Literal::ArgumentError) do 93 result.and_then(&:to_s) 94 end 95 96 assert_equal "Expected block to return a Literal::Result, got String", error.message 97end 98 99test "failure map updates success type metadata" do 100 result = Literal::Result(Integer, Symbol) { |type| type.failure(:nope) } 101 mapped = result.map(String, &:to_s) 102 103 assert mapped.failure? 104 assert_equal :nope, mapped.error! 105 assert_equal String, mapped.success_type 106 assert_equal Symbol, mapped.failure_type 107end 108 109test "success deconstruct_keys delegates to wrapped value" do 110 person_class = Class.new do 111 def initialize(name) 112 @name = name 113 end 114 115 def deconstruct_keys(keys) 116 h = { name: @name } 117 keys ? h.slice(*keys) : h 118 end 119 end 120 121 result = Literal::Result(person_class, Symbol) { |type| type.success(person_class.new("Joel")) } 122 123 assert_equal({ name: "Joel" }, result.deconstruct_keys([:name])) 124 assert_equal({}, result.deconstruct_keys([:value])) 125end 126 127test "failure deconstruct_keys delegates to wrapped error" do 128 error_class = Class.new do 129 def initialize(message) 130 @message = message 131 end 132 133 def deconstruct_keys(keys) 134 h = { message: @message } 135 keys ? h.slice(*keys) : h 136 end 137 end 138 139 result = Literal::Result(String, error_class) { |type| type.failure(error_class.new("oops")) } 140 141 assert_equal({ message: "oops" }, result.deconstruct_keys([:message])) 142 assert_equal({}, result.deconstruct_keys([:error])) 143end 144 145test "deconstruct_keys returns empty hash when wrapped object does not support it" do 146 success = Literal::Result(Integer, Symbol) { |type| type.success(1) } 147 failure = Literal::Result(String, Symbol) { |type| type.failure(:oops) } 148 149 assert_equal({}, success.deconstruct_keys([:anything])) 150 assert_equal({}, failure.deconstruct_keys([:anything])) 151end 152 153test "pattern matches success with positional pattern" do 154 result = Literal::Result(Integer, Symbol) { |type| type.success(1) } 155 156 matched = case result 157 in Literal::Success[Integer] 158 true 159 else 160 false 161 end 162 163 assert matched 164end 165 166test "pattern matches success with delegated keyword pattern" do 167 message_class = Class.new do 168 def initialize(message) 169 @message = message 170 end 171 172 def deconstruct_keys(keys) 173 h = { message: @message } 174 keys ? h.slice(*keys) : h 175 end 176 end 177 178 result = Literal::Result(message_class, Symbol) { |type| type.success(message_class.new("Hello")) } 179 180 matched = case result 181 in Literal::Success[message: "Hello"] 182 true 183 else 184 false 185 end 186 187 assert matched 188end