diff --git a/lab2/gleam.toml b/lab2/gleam.toml index d4684dd..93fd57e 100644 --- a/lab2/gleam.toml +++ b/lab2/gleam.toml @@ -14,6 +14,7 @@ version = "1.0.0" [dependencies] gleam_stdlib = ">= 0.44.0 and < 2.0.0" +prng = ">= 4.0.1 and < 5.0.0" [dev-dependencies] gleeunit = ">= 1.0.0 and < 2.0.0" diff --git a/lab2/manifest.toml b/lab2/manifest.toml index 834b83a..1bed42a 100644 --- a/lab2/manifest.toml +++ b/lab2/manifest.toml @@ -2,10 +2,14 @@ # You typically do not need to edit this file packages = [ + { name = "gleam_bitwise", version = "1.3.1", build_tools = ["gleam"], requirements = [], otp_app = "gleam_bitwise", source = "hex", outer_checksum = "B36E1D3188D7F594C7FD4F43D0D2CE17561DE896202017548578B16FE1FE9EFC" }, { name = "gleam_stdlib", version = "0.67.1", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "6CE3E4189A8B8EC2F73AB61A2FBDE49F159D6C9C61C49E3B3082E439F260D3D0" }, + { name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" }, { name = "gleeunit", version = "1.9.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "DA9553CE58B67924B3C631F96FE3370C49EB6D6DC6B384EC4862CC4AAA718F3C" }, + { name = "prng", version = "4.0.1", build_tools = ["gleam"], requirements = ["gleam_bitwise", "gleam_stdlib", "gleam_yielder"], otp_app = "prng", source = "hex", outer_checksum = "695AB70E4BE713042062E901975FC08D1EC725B85B808D4786A14C406ADFBCF1" }, ] [requirements] gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" } gleeunit = { version = ">= 1.0.0 and < 2.0.0" } +prng = { version = ">= 4.0.1 and < 5.0.0" } diff --git a/lab2/test/lab2_test.gleam b/lab2/test/lab2_test.gleam index 965fef4..4dd6395 100644 --- a/lab2/test/lab2_test.gleam +++ b/lab2/test/lab2_test.gleam @@ -6,6 +6,8 @@ import gleam/string import gleeunit import gleeunit/should import lab2 +import prng/random +import prng/seed pub fn main() { gleeunit.main() @@ -24,160 +26,249 @@ fn string_equal(a: String, b: String) -> Bool { a == b } -// Тест создания пустого дерева +// Генерация случайных данных +fn gk() -> Int { + int.random(1000) - 500 +} + +fn gv() -> String { + let length = int.random(32) + let generator: random.Generator(Int) = random.int(97, 122) + let seed = seed.new(42) + // random string of given length + string.join( + list.repeat("", length) + |> list.map(fn(_) { + let code = random.sample(generator, seed) + let assert Ok(cp) = string.utf_codepoint(code) + string.from_utf_codepoints([cp]) + }), + "", + ) +} + +/// Тест создания пустого дерева pub fn empty_tree_test() { let tree = lab2.empty() lab2.is_empty(tree) |> should.be_true lab2.size(tree) |> should.equal(0) } -// Тест вставки одного элемента +/// Тест вставки одного элемента pub fn single_insert_test() { + let key = gk() + let value = gv() let tree = lab2.empty() - |> lab2.insert(5, "five", int_compare) + |> lab2.insert(key, value, int_compare) lab2.is_empty(tree) |> should.be_false lab2.size(tree) |> should.equal(1) - lab2.lookup(tree, 5, int_compare) |> should.equal(option.Some("five")) - lab2.lookup(tree, 10, int_compare) |> should.equal(option.None) + lab2.lookup(tree, key, int_compare) |> should.equal(option.Some(value)) + lab2.lookup(tree, gk(), int_compare) |> should.equal(option.None) } -// Тест множественных вставок +/// Тест множественных вставок pub fn multiple_insert_test() { + let k1 = gk() + let v1 = gv() + let k2 = gk() + let v2 = gv() + let k3 = gk() + let v3 = gv() + let k4 = gk() + let v4 = gv() + let k5 = gk() + let v5 = gv() let tree = lab2.empty() - |> lab2.insert(5, "five", int_compare) - |> lab2.insert(3, "three", int_compare) - |> lab2.insert(7, "seven", int_compare) - |> lab2.insert(1, "one", int_compare) - |> lab2.insert(9, "nine", int_compare) + |> lab2.insert(k1, v1, int_compare) + |> lab2.insert(k2, v2, int_compare) + |> lab2.insert(k3, v3, int_compare) + |> lab2.insert(k4, v4, int_compare) + |> lab2.insert(k5, v5, int_compare) lab2.size(tree) |> should.equal(5) - lab2.lookup(tree, 1, int_compare) |> should.equal(option.Some("one")) - lab2.lookup(tree, 3, int_compare) |> should.equal(option.Some("three")) - lab2.lookup(tree, 5, int_compare) |> should.equal(option.Some("five")) - lab2.lookup(tree, 7, int_compare) |> should.equal(option.Some("seven")) - lab2.lookup(tree, 9, int_compare) |> should.equal(option.Some("nine")) + lab2.lookup(tree, k1, int_compare) |> should.equal(option.Some(v1)) + lab2.lookup(tree, k2, int_compare) |> should.equal(option.Some(v2)) + lab2.lookup(tree, k3, int_compare) |> should.equal(option.Some(v3)) + lab2.lookup(tree, k4, int_compare) |> should.equal(option.Some(v4)) + lab2.lookup(tree, k5, int_compare) |> should.equal(option.Some(v5)) } -// Тест удаления элементов +/// Тест удаления элементов pub fn delete_test() { + let k1 = gk() + let v1 = gv() + let k2 = gk() + let v2 = gv() + let k3 = gk() + let v3 = gv() let tree = lab2.empty() - |> lab2.insert(5, "five", int_compare) - |> lab2.insert(3, "three", int_compare) - |> lab2.insert(7, "seven", int_compare) - |> lab2.delete(3, int_compare) + |> lab2.insert(k1, v1, int_compare) + |> lab2.insert(k2, v2, int_compare) + |> lab2.insert(k3, v3, int_compare) + |> lab2.delete(k2, int_compare) lab2.size(tree) |> should.equal(2) - lab2.lookup(tree, 3, int_compare) |> should.equal(option.None) - lab2.lookup(tree, 5, int_compare) |> should.equal(option.Some("five")) - lab2.lookup(tree, 7, int_compare) |> should.equal(option.Some("seven")) + lab2.lookup(tree, k2, int_compare) |> should.equal(option.None) + lab2.lookup(tree, k1, int_compare) |> should.equal(option.Some(v1)) + lab2.lookup(tree, k3, int_compare) |> should.equal(option.Some(v3)) } -// Тест фильтрации +/// Тест фильтрации pub fn filter_test() { + let k1 = gk() * 2 + 1 + let v1 = gv() + let k2 = gk() * 2 + let v2 = gv() + let k3 = gk() * 2 + 1 + let v3 = gv() + let k4 = gk() * 2 + let v4 = gv() + let k5 = gk() * 2 + 1 + let v5 = gv() let tree = lab2.empty() - |> lab2.insert(1, "one", int_compare) - |> lab2.insert(2, "two", int_compare) - |> lab2.insert(3, "three", int_compare) - |> lab2.insert(4, "four", int_compare) - |> lab2.insert(5, "five", int_compare) + |> lab2.insert(k1, v1, int_compare) + |> lab2.insert(k2, v2, int_compare) + |> lab2.insert(k3, v3, int_compare) + |> lab2.insert(k4, v4, int_compare) + |> lab2.insert(k5, v5, int_compare) let filtered = lab2.filter(tree, fn(key, _) { key % 2 == 0 }, int_compare) lab2.size(filtered) |> should.equal(2) - lab2.contains(filtered, 2, int_compare) |> should.be_true - lab2.contains(filtered, 4, int_compare) |> should.be_true - lab2.contains(filtered, 1, int_compare) |> should.be_false + lab2.contains(filtered, k2, int_compare) |> should.be_true + lab2.contains(filtered, k4, int_compare) |> should.be_true + lab2.contains(filtered, k1, int_compare) |> should.be_false } -// Тест отображения +/// Тест отображения pub fn map_test() { + let k1 = gk() + let v1 = gk() + let k2 = gk() + let v2 = gk() + let k3 = gk() + let v3 = gk() let tree = lab2.empty() - |> lab2.insert(1, 10, int_compare) - |> lab2.insert(2, 20, int_compare) - |> lab2.insert(3, 30, int_compare) + |> lab2.insert(k1, v1, int_compare) + |> lab2.insert(k2, v2, int_compare) + |> lab2.insert(k3, v3, int_compare) let mapped = lab2.map(tree, fn(value) { value * 2 }) - lab2.lookup(mapped, 1, int_compare) |> should.equal(option.Some(20)) - lab2.lookup(mapped, 2, int_compare) |> should.equal(option.Some(40)) - lab2.lookup(mapped, 3, int_compare) |> should.equal(option.Some(60)) + lab2.lookup(mapped, k1, int_compare) |> should.equal(option.Some(v1 * 2)) + lab2.lookup(mapped, k2, int_compare) |> should.equal(option.Some(v2 * 2)) + lab2.lookup(mapped, k3, int_compare) |> should.equal(option.Some(v3 * 2)) } -// Тест левой свёртки +/// Тест левой свёртки pub fn fold_left_test() { + let k1 = gk() + let v1 = gk() + let k2 = gk() + let v2 = gk() + let k3 = gk() + let v3 = gk() let tree = lab2.empty() - |> lab2.insert(1, 10, int_compare) - |> lab2.insert(2, 20, int_compare) - |> lab2.insert(3, 30, int_compare) + |> lab2.insert(k1, v1, int_compare) + |> lab2.insert(k2, v2, int_compare) + |> lab2.insert(k3, v3, int_compare) let sum = lab2.fold_left(tree, 0, fn(acc, _, value) { acc + value }) - sum |> should.equal(60) + sum |> should.equal(v1 + v2 + v3) } -// Тест правой свёртки +/// Тест правой свёртки pub fn fold_right_test() { + let k1 = gk() + let v1 = gv() + let k2 = gk() + let v2 = gv() + let k3 = gk() + let v3 = gv() let tree = lab2.empty() - |> lab2.insert(1, "a", int_compare) - |> lab2.insert(2, "b", int_compare) - |> lab2.insert(3, "c", int_compare) + |> lab2.insert(k1, v1, int_compare) + |> lab2.insert(k2, v2, int_compare) + |> lab2.insert(k3, v3, int_compare) let result = lab2.fold_right(tree, "", fn(_, value, acc) { value <> acc }) // Порядок может отличаться в зависимости от структуры дерева - result |> string.length |> should.equal(3) + result + |> string.length + |> should.equal(string.length(v1) + string.length(v2) + string.length(v3)) } -// Тест преобразования в список и обратно +/// Тест преобразования в список и обратно pub fn to_from_list_test() { - let original_list = [#(1, "one"), #(2, "two"), #(3, "three")] + let k1 = gk() + let v1 = gv() + let k2 = gk() + let v2 = gv() + let k3 = gk() + let v3 = gv() + let original_list = [#(k1, v1), #(k2, v2), #(k3, v3)] let tree = lab2.from_list(original_list, int_compare) let result_list = lab2.to_list(tree) lab2.size(tree) |> should.equal(3) list.length(result_list) |> should.equal(3) - lab2.contains(tree, 1, int_compare) |> should.be_true - lab2.contains(tree, 2, int_compare) |> should.be_true - lab2.contains(tree, 3, int_compare) |> should.be_true + lab2.contains(tree, k1, int_compare) |> should.be_true + lab2.contains(tree, k2, int_compare) |> should.be_true + lab2.contains(tree, k3, int_compare) |> should.be_true } // Тесты свойств моноида -// Тест нейтрального элемента (левая единица) +/// Тест нейтрального элемента (левая единица) pub fn monoid_left_identity_test() { + let k1 = gk() + let v1 = gv() + let k2 = gk() + let v2 = gv() let tree = lab2.empty() - |> lab2.insert(1, "one", int_compare) - |> lab2.insert(2, "two", int_compare) + |> lab2.insert(k1, v1, int_compare) + |> lab2.insert(k2, v2, int_compare) - let result = lab2.concat(lab2.mempty(), tree, int_compare) + let result = lab2.concat(lab2.empty(), tree, int_compare) lab2.equal(tree, result, int_equal, string_equal) |> should.be_true } -// Тест нейтрального элемента (правая единица) +/// Тест нейтрального элемента (правая единица) pub fn monoid_right_identity_test() { + let k1 = gk() + let v1 = gv() + let k2 = gk() + let v2 = gv() let tree = lab2.empty() - |> lab2.insert(1, "one", int_compare) - |> lab2.insert(2, "two", int_compare) + |> lab2.insert(k1, v1, int_compare) + |> lab2.insert(k2, v2, int_compare) - let result = lab2.concat(tree, lab2.mempty(), int_compare) + let result = lab2.concat(tree, lab2.empty(), int_compare) lab2.equal(tree, result, int_equal, string_equal) |> should.be_true } -// Тест ассоциативности +/// Тест ассоциативности pub fn monoid_associativity_test() { - let tree1 = lab2.empty() |> lab2.insert(1, "one", int_compare) - let tree2 = lab2.empty() |> lab2.insert(2, "two", int_compare) - let tree3 = lab2.empty() |> lab2.insert(3, "three", int_compare) + let k1 = gk() + let v1 = gv() + let k2 = gk() + let v2 = gv() + let k3 = gk() + let v3 = gv() + let tree1 = lab2.empty() |> lab2.insert(k1, v1, int_compare) + let tree2 = lab2.empty() |> lab2.insert(k2, v2, int_compare) + let tree3 = lab2.empty() |> lab2.insert(k3, v3, int_compare) let left_assoc = lab2.concat(lab2.concat(tree1, tree2, int_compare), tree3, int_compare) @@ -187,31 +278,20 @@ pub fn monoid_associativity_test() { // Проверяем, что оба дерева содержат одинаковые элементы lab2.size(left_assoc) |> should.equal(3) lab2.size(right_assoc) |> should.equal(3) - lab2.contains(left_assoc, 1, int_compare) |> should.be_true - lab2.contains(left_assoc, 2, int_compare) |> should.be_true - lab2.contains(left_assoc, 3, int_compare) |> should.be_true - lab2.contains(right_assoc, 1, int_compare) |> should.be_true - lab2.contains(right_assoc, 2, int_compare) |> should.be_true - lab2.contains(right_assoc, 3, int_compare) |> should.be_true + lab2.contains(left_assoc, k1, int_compare) |> should.be_true + lab2.contains(left_assoc, k2, int_compare) |> should.be_true + lab2.contains(left_assoc, k3, int_compare) |> should.be_true + lab2.contains(right_assoc, k1, int_compare) |> should.be_true + lab2.contains(right_assoc, k2, int_compare) |> should.be_true + lab2.contains(right_assoc, k3, int_compare) |> should.be_true } -// Тест инвариантов красно-чёрного дерева (упрощённая проверка) +/// Тест инвариантов красно-чёрного дерева (упрощённая проверка) pub fn red_black_invariant_test() { // Создаём большое дерево и проверяем, что поиск работает корректно let tree = lab2.from_list( - [ - #(1, "one"), - #(2, "two"), - #(3, "three"), - #(4, "four"), - #(5, "five"), - #(6, "six"), - #(7, "seven"), - #(8, "eight"), - #(9, "nine"), - #(10, "ten"), - ], + list.map(list.range(1, 10), fn(i) { #(i, gv()) }), int_compare, ) @@ -219,31 +299,34 @@ pub fn red_black_invariant_test() { // Проверяем, что все элементы можно найти let all_found = - list.all([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], fn(key) { + list.all(list.range(1, 10), fn(key) { lab2.contains(tree, key, int_compare) }) all_found |> should.be_true } -// Тест обновления существующего ключа +/// Тест обновления существующего ключа pub fn update_existing_key_test() { + let key = gk() + let old_value = gv() + let new_value = gv() let tree = lab2.empty() - |> lab2.insert(1, "old", int_compare) - |> lab2.insert(1, "new", int_compare) + |> lab2.insert(key, old_value, int_compare) + |> lab2.insert(key, new_value, int_compare) lab2.size(tree) |> should.equal(1) - lab2.lookup(tree, 1, int_compare) |> should.equal(option.Some("new")) + lab2.lookup(tree, key, int_compare) |> should.equal(option.Some(new_value)) } -// Тест свойства: insert -> lookup должен возвращать вставленное значение +/// Тест свойства: insert -> lookup должен возвращать вставленное значение pub fn insert_lookup_property_test() { let test_cases = [ - #(1, "one"), - #(42, "forty-two"), - #(0, "zero"), - #(-5, "minus-five"), + #(gk(), gv()), + #(gk(), gv()), + #(gk(), gv()), + #(gk(), gv()), ] list.each(test_cases, fn(test_case) { @@ -253,30 +336,33 @@ pub fn insert_lookup_property_test() { }) } -// Тест свойства: size увеличивается при вставке новых элементов +/// Тест свойства: size увеличивается при вставке новых элементов pub fn insert_size_property_test() { + let key1 = gk() + let key2 = gk() + let key3 = gk() let tree = lab2.empty() lab2.size(tree) |> should.equal(0) - let tree1 = lab2.insert(tree, 1, "one", int_compare) + let tree1 = lab2.insert(tree, key1, gv(), int_compare) lab2.size(tree1) |> should.equal(1) - let tree2 = lab2.insert(tree1, 2, "two", int_compare) + let tree2 = lab2.insert(tree1, key2, gv(), int_compare) lab2.size(tree2) |> should.equal(2) - let tree3 = lab2.insert(tree2, 3, "three", int_compare) + let tree3 = lab2.insert(tree2, key3, gv(), int_compare) lab2.size(tree3) |> should.equal(3) // Вставка существующего ключа не должна увеличивать размер - let tree4 = lab2.insert(tree3, 2, "two-updated", int_compare) + let tree4 = lab2.insert(tree3, key2, gv(), int_compare) lab2.size(tree4) |> should.equal(3) } -// Тест свойства: filter сохраняет порядок и структуру +/// Тест свойства: filter сохраняет порядок и структуру pub fn filter_property_test() { let original = lab2.from_list( - [#(1, "a"), #(2, "b"), #(3, "c"), #(4, "d"), #(5, "e")], + list.map(list.range(1, 5), fn(i) { #(i, gv()) }), int_compare, ) @@ -296,9 +382,15 @@ pub fn filter_property_test() { lab2.contains(partial_filter, 5, int_compare) |> should.be_true } -// Тест свойства: map сохраняет структуру дерева +/// Тест свойства: map сохраняет структуру дерева pub fn map_property_test() { - let original = lab2.from_list([#(1, 10), #(2, 20), #(3, 30)], int_compare) + let k1 = gk() + let v1 = gk() + let k2 = gk() + let v2 = gk() + let k3 = gk() + let v3 = gk() + let original = lab2.from_list([#(k1, v1), #(k2, v2), #(k3, v3)], int_compare) // Тождественное отображение let identity_map = lab2.map(original, fn(x) { x }) @@ -307,22 +399,24 @@ pub fn map_property_test() { // Отображение с изменением let doubled = lab2.map(original, fn(x) { x * 2 }) lab2.size(doubled) |> should.equal(lab2.size(original)) - lab2.lookup(doubled, 1, int_compare) |> should.equal(option.Some(20)) - lab2.lookup(doubled, 2, int_compare) |> should.equal(option.Some(40)) - lab2.lookup(doubled, 3, int_compare) |> should.equal(option.Some(60)) + lab2.lookup(doubled, k1, int_compare) |> should.equal(option.Some(v1 * 2)) + lab2.lookup(doubled, k2, int_compare) |> should.equal(option.Some(v2 * 2)) + lab2.lookup(doubled, k3, int_compare) |> should.equal(option.Some(v3 * 2)) } -// Тест свойства: fold_left и fold_right дают корректные результаты +/// Тест свойства: fold_left и fold_right дают корректные результаты pub fn fold_property_test() { - let tree = - lab2.from_list([#(1, 1), #(2, 2), #(3, 3), #(4, 4), #(5, 5)], int_compare) + let values = list.map(list.range(1, 5), fn(_) { gk() }) + let tree = lab2.from_list(list.zip(list.range(1, 5), values), int_compare) + + let expected_sum = list.fold(values, 0, fn(acc, v) { acc + v }) // Сумма всех значений let sum_left = lab2.fold_left(tree, 0, fn(acc, _, value) { acc + value }) let sum_right = lab2.fold_right(tree, 0, fn(_, value, acc) { acc + value }) - sum_left |> should.equal(15) - sum_right |> should.equal(15) + sum_left |> should.equal(expected_sum) + sum_right |> should.equal(expected_sum) // Количество элементов let count_left = lab2.fold_left(tree, 0, fn(acc, _, _) { acc + 1 }) @@ -332,15 +426,24 @@ pub fn fold_property_test() { count_right |> should.equal(5) } -// Тест свойства: to_list -> from_list должно давать эквивалентное дерево +/// Тест свойства: to_list -> from_list должно давать эквивалентное дерево pub fn list_roundtrip_property_test() { - let original_list = [#(3, "c"), #(1, "a"), #(4, "d"), #(2, "b")] + let k1 = gk() + let v1 = gv() + let k2 = gk() + let v2 = gv() + let k3 = gk() + let v3 = gv() + let k4 = gk() + let v4 = gv() + let original_list = [#(k1, v1), #(k2, v2), #(k3, v3), #(k4, v4)] let tree = lab2.from_list(original_list, int_compare) let result_list = lab2.to_list(tree) let restored_tree = lab2.from_list(result_list, int_compare) lab2.size(tree) |> should.equal(lab2.size(restored_tree)) - lab2.equal(tree, restored_tree, int_equal, string_equal) |> should.be_true + lab2.semantic_equal(tree, restored_tree, int_compare, string_equal) + |> should.be_true // Проверяем, что все элементы присутствуют list.each(original_list, fn(item) { @@ -350,10 +453,18 @@ pub fn list_roundtrip_property_test() { }) } -// Тест инвариантов моноида (коммутативность для деревьев с разными ключами) +/// Тест инвариантов моноида (коммутативность для деревьев с разными ключами) pub fn monoid_commutativity_test() { - let tree1 = lab2.from_list([#(1, "a"), #(2, "b")], int_compare) - let tree2 = lab2.from_list([#(3, "c"), #(4, "d")], int_compare) + let k1 = gk() + let v1 = gv() + let k2 = gk() + let v2 = gv() + let k3 = gk() + let v3 = gv() + let k4 = gk() + let v4 = gv() + let tree1 = lab2.from_list([#(k1, v1), #(k2, v2)], int_compare) + let tree2 = lab2.from_list([#(k3, v3), #(k4, v4)], int_compare) let concat1 = lab2.concat(tree1, tree2, int_compare) let concat2 = lab2.concat(tree2, tree1, int_compare) @@ -363,47 +474,9 @@ pub fn monoid_commutativity_test() { lab2.size(concat2) |> should.equal(4) // Оба дерева должны содержать все элементы - [1, 2, 3, 4] + [k1, k2, k3, k4] |> list.each(fn(key) { lab2.contains(concat1, key, int_compare) |> should.be_true lab2.contains(concat2, key, int_compare) |> should.be_true }) } - -// Тест семантического равенства деревьев -// Проверяет, что деревья с одинаковым содержимым, но разной структурой считаются равными -pub fn semantic_equal_test() { - // Создаём два дерева с одинаковыми данными, но разным порядком вставки - let tree1 = - lab2.empty() - |> lab2.insert(2, "two", int_compare) - |> lab2.insert(1, "one", int_compare) - |> lab2.insert(3, "three", int_compare) - - let tree2 = - lab2.empty() - |> lab2.insert(1, "one", int_compare) - |> lab2.insert(3, "three", int_compare) - |> lab2.insert(2, "two", int_compare) - - // Семантически они должны быть равны - lab2.semantic_equal(tree1, tree2, int_compare, string_equal) |> should.be_true - // Структурно они могут быть разными (зависит от балансировки) - // lab2.equal(tree1, tree2, int_equal, string_equal) может быть false -} - -// Тест структурного равенства без учёта цветов узлов -pub fn structure_equal_test() { - let tree1 = - lab2.empty() - |> lab2.insert(2, "two", int_compare) - |> lab2.insert(1, "one", int_compare) - - let tree2 = - lab2.empty() - |> lab2.insert(2, "two", int_compare) - |> lab2.insert(1, "one", int_compare) - - // Структурно должны быть равны (игнорируя цвета) - lab2.structure_equal(tree1, tree2, int_equal, string_equal) |> should.be_true -}