From 9895655a8ab78c2c92e1e2f7d8b7c6c196157a20 Mon Sep 17 00:00:00 2001 From: Luis Lavena Date: Sun, 12 Mar 2017 12:36:05 -0300 Subject: [PATCH] Fix incorrect lookup on non-shared partial keys Given the following nodes in a tree: # ( 8) /product # ( 4) /new # ( 1) s tree = Radix::Tree(Symbol).new tree.add "/products", :products tree.add "/product/new", :product_new It failed to properly identify `/products` during lookup: result = tree.find "/products" result.found? # => false Caused by incorrect comparsion of `s` remaining path against `/new` node instead of continue comparison with the next one. Fixes #21 --- CHANGELOG.md | 2 ++ spec/radix/tree_spec.cr | 11 +++++++++++ src/radix/tree.cr | 6 ++++++ 3 files changed, 19 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8976356..cc2579b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ This project aims to comply with [Semantic Versioning](http://semver.org/), so please check *Changed* and *Removed* notes before upgrading. ## [Unreleased] +### Fixed +- Correct lookup issue caused by incorrect comparison of shared key [#21](https://github.com/luislavena/radix/issues/21) ## [0.3.7] - 2017-02-04 ### Fixed diff --git a/spec/radix/tree_spec.cr b/spec/radix/tree_spec.cr index 4c8ce04..3f100a7 100644 --- a/spec/radix/tree_spec.cr +++ b/spec/radix/tree_spec.cr @@ -323,6 +323,17 @@ module Radix result.payload.should eq(:abc) end + it "finds matching path across separator" do + tree = Tree(Symbol).new + tree.add "/products", :products + tree.add "/product/new", :product_new + + result = tree.find("/products") + result.found?.should be_true + result.key.should eq("/products") + result.payload.should eq(:products) + end + it "finds matching path across parents" do tree = Tree(Symbol).new tree.add "/", :root diff --git a/src/radix/tree.cr b/src/radix/tree.cr index 49d910b..f65cb54 100644 --- a/src/radix/tree.cr +++ b/src/radix/tree.cr @@ -432,11 +432,17 @@ module Radix # _shared_key?("foo", "bar") # => false (mismatch at 1st character) # _shared_key?("foo/bar", "foo/baz") # => true (only `foo` is compared) # _shared_key?("zipcode", "zip") # => true (only `zip` is compared) + # _shared_key?("s", "/new") # => false (1st character is a separator) # ``` private def _shared_key?(path, key) path_reader = Char::Reader.new(path) key_reader = Char::Reader.new(key) + if (path_reader.current_char != key_reader.current_char) && + _check_markers(key_reader.current_char) + return false + end + different = false while (path_reader.has_next? && !_check_markers(path_reader.current_char)) &&