Last failing spec

This commit is contained in:
Serdar Dogruyol 2016-04-14 18:34:52 +03:00
parent e65c789d2c
commit 8f62dadc92
5 changed files with 208 additions and 126 deletions

View file

@ -4,7 +4,7 @@ module Radix
describe Node do
describe "#key=" do
it "accepts change of key after initialization" do
node = Node(TestPayload).new("abc")
node = Node(TestPayload).new("abc", nil)
node.key.should eq("abc")
node.key = "xyz"
@ -25,38 +25,38 @@ module Radix
end
it "makes optional to provide a payload" do
node = Node(TestPayload).new("abc")
node = Node(TestPayload).new("abc", nil)
node.payload?.should be_falsey
end
end
describe "#priority" do
it "calculates it based on key size" do
node = Node(TestPayload).new("a")
node = Node(TestPayload).new("a", nil)
node.priority.should eq(1)
node = Node(TestPayload).new("abc")
node = Node(TestPayload).new("abc", nil)
node.priority.should eq(3)
end
it "returns zero for catch all (globbed) key" do
node = Node(TestPayload).new("*filepath")
node = Node(TestPayload).new("*filepath", nil)
node.priority.should eq(0)
node = Node(TestPayload).new("/src/*filepath")
node = Node(TestPayload).new("/src/*filepath", nil)
node.priority.should eq(0)
end
it "returns one for keys with named parameters" do
node = Node(TestPayload).new(":query")
node = Node(TestPayload).new(":query", nil)
node.priority.should eq(1)
node = Node(TestPayload).new("/search/:query")
node = Node(TestPayload).new("/search/:query", nil)
node.priority.should eq(1)
end
it "changes when key changes" do
node = Node(TestPayload).new("a")
node = Node(TestPayload).new("a", nil)
node.priority.should eq(1)
node.key = "abc"
@ -72,10 +72,10 @@ module Radix
describe "#sort!" do
it "orders children by priority" do
root = Node(TestPayload).new("/")
node1 = Node(TestPayload).new("a")
node2 = Node(TestPayload).new("bc")
node3 = Node(TestPayload).new("def")
root = Node(TestPayload).new("/", nil)
node1 = Node(TestPayload).new("a", nil)
node2 = Node(TestPayload).new("bc", nil)
node3 = Node(TestPayload).new("def", nil)
root.children.push(node1, node2, node3)
root.sort!
@ -86,10 +86,10 @@ module Radix
end
it "orders catch all and named parameters lower than others" do
root = Node(TestPayload).new("/")
node1 = Node(TestPayload).new("*filepath")
node2 = Node(TestPayload).new("abc")
node3 = Node(TestPayload).new(":query")
root = Node(TestPayload).new("/", nil)
node1 = Node(TestPayload).new("*filepath", nil)
node2 = Node(TestPayload).new("abc", nil)
node3 = Node(TestPayload).new(":query", nil)
root.children.push(node1, node2, node3)
root.sort!

View file

@ -13,7 +13,7 @@ module Radix
context "with a payload" do
it "returns true" do
payload = TestPayload.new
node = Node.new("/", payload)
node = Node(TestPayload).new("/", payload)
result = Result(TestPayload).new
result.use node
@ -33,7 +33,7 @@ module Radix
context "given one used node" do
it "returns the node key" do
payload = TestPayload.new
node = Node.new("/", payload)
node = Node(TestPayload).new("/", payload)
result = Result(TestPayload).new
result.use node
@ -44,8 +44,8 @@ module Radix
context "using multiple nodes" do
it "combines the node keys" do
payload = TestPayload.new
node1 = Node.new("/", payload)
node2 = Node.new("about", payload)
node1 = Node(TestPayload).new("/", payload)
node2 = Node(TestPayload).new("about", payload)
result = Result(TestPayload).new
result.use node1
result.use node2
@ -58,7 +58,7 @@ module Radix
describe "#use" do
it "uses the node payload" do
payload = TestPayload.new
node = Node.new("/", payload)
node = Node(TestPayload).new("/", payload)
result = Result(TestPayload).new
result.payload?.should be_falsey
@ -69,7 +69,7 @@ module Radix
it "allow not to assign payload" do
payload = TestPayload.new
node = Node.new("/", payload)
node = Node(TestPayload).new("/", payload)
result = Result(TestPayload).new
result.payload?.should be_falsey

View file

@ -26,7 +26,7 @@ module Radix
it "contains a root placeholder node" do
payload = TestPayload.new
tree = Tree(TestPayload).new
tree.root.should be_a(Node)
tree.root.should be_a(Node(TestPayload))
tree.root.payload?.should be_falsey
tree.root.placeholder?.should be_true
end
@ -35,37 +35,44 @@ module Radix
describe "#add" do
context "on a new instance" do
it "replaces placeholder with new node" do
payload = TestPayload.new
tree = Tree(TestPayload).new
tree.add "/abc", :abc
tree.root.should be_a(Node)
tree.add "/abc", payload
tree.root.should be_a(Node(TestPayload))
tree.root.placeholder?.should be_false
tree.root.payload?.should be_truthy
tree.root.payload.should eq(:abc)
tree.root.payload.should eq(payload)
end
end
context "shared root" do
it "inserts properly adjacent nodes" do
root_payload = TestPayload.new
a_payload = TestPayload.new
bc_payload = TestPayload.new
tree = Tree(TestPayload).new
tree.add "/", :root
tree.add "/a", :a
tree.add "/bc", :bc
tree.add "/", root_payload
tree.add "/a", a_payload
tree.add "/bc", bc_payload
# / (:root)
# +-bc (:bc)
# \-a (:a)
tree.root.children.size.should eq(2)
tree.root.children[0].key.should eq("bc")
tree.root.children[0].payload.should eq(:bc)
tree.root.children[0].payload.should eq(bc_payload)
tree.root.children[1].key.should eq("a")
tree.root.children[1].payload.should eq(:a)
tree.root.children[1].payload.should eq(a_payload)
end
it "inserts nodes with shared parent" do
root_payload = TestPayload.new
abc_payload = TestPayload.new
axyz_payload = TestPayload.new
tree = Tree(TestPayload).new
tree.add "/", :root
tree.add "/abc", :abc
tree.add "/axyz", :axyz
tree.add "/", root_payload
tree.add "/abc", abc_payload
tree.add "/axyz", axyz_payload
# / (:root)
# +-a
@ -79,12 +86,17 @@ module Radix
end
it "inserts multiple parent nodes" do
root_payload = TestPayload.new
users_payload = TestPayload.new
products_payload = TestPayload.new
tags_payload = TestPayload.new
articles_payload = TestPayload.new
tree = Tree(TestPayload).new
tree.add "/", :root
tree.add "/admin/users", :users
tree.add "/admin/products", :products
tree.add "/blog/tags", :tags
tree.add "/blog/articles", :articles
tree.add "/", root_payload
tree.add "/admin/users", users_payload
tree.add "/admin/products", products_payload
tree.add "/blog/tags", tags_payload
tree.add "/blog/articles", articles_payload
# / (:root)
# +-admin/
@ -108,11 +120,15 @@ module Radix
end
it "inserts multiple nodes with mixed parents" do
authorizations_payload = TestPayload.new
authorization_payload = TestPayload.new
applications_payload = TestPayload.new
events_payload = TestPayload.new
tree = Tree(TestPayload).new
tree.add "/authorizations", :authorizations
tree.add "/authorizations/:id", :authorization
tree.add "/applications", :applications
tree.add "/events", :events
tree.add "/authorizations", authorizations_payload
tree.add "/authorizations/:id", authorization_payload
tree.add "/applications", applications_payload
tree.add "/events", events_payload
# /
# +-events (:events)
@ -123,16 +139,20 @@ module Radix
tree.root.children.size.should eq(2)
tree.root.children[1].key.should eq("a")
tree.root.children[1].children.size.should eq(2)
tree.root.children[1].children[0].payload.should eq(:authorizations)
tree.root.children[1].children[1].payload.should eq(:applications)
tree.root.children[1].children[0].payload.should eq(authorizations_payload)
tree.root.children[1].children[1].payload.should eq(applications_payload)
end
it "supports insertion of mixed routes out of order" do
my_repos_payload = TestPayload.new
user_repos_payload = TestPayload.new
user_payload = TestPayload.new
me_payload = TestPayload.new
tree = Tree(TestPayload).new
tree.add "/user/repos", :my_repos
tree.add "/users/:user/repos", :user_repos
tree.add "/users/:user", :user
tree.add "/user", :me
tree.add "/user/repos", my_repos_payload
tree.add "/users/:user/repos", user_repos_payload
tree.add "/users/:user", user_payload
tree.add "/user", me_payload
# /user (:me)
# +-/repos (:my_repos)
@ -140,23 +160,26 @@ module Radix
# \-/repos (:user_repos)
tree.root.key.should eq("/user")
tree.root.payload?.should be_truthy
tree.root.payload.should eq(:me)
tree.root.payload.should eq(me_payload)
tree.root.children.size.should eq(2)
tree.root.children[0].key.should eq("/repos")
tree.root.children[1].key.should eq("s/:user")
tree.root.children[1].payload.should eq(:user)
tree.root.children[1].payload.should eq(user_payload)
tree.root.children[1].children[0].key.should eq("/repos")
end
end
context "dealing with duplicates" do
it "does not allow same path be defined twice" do
root_payload = TestPayload.new
abc_payload = TestPayload.new
other_payload = TestPayload.new
tree = Tree(TestPayload).new
tree.add "/", :root
tree.add "/abc", :abc
tree.add "/", root_payload
tree.add "/abc", abc_payload
expect_raises Tree::DuplicateError do
tree.add "/", :other
tree.add "/", other_payload
end
tree.root.children.size.should eq(1)
@ -165,13 +188,19 @@ module Radix
context "dealing with catch all and named parameters" do
it "prioritizes nodes correctly" do
root_payload = TestPayload.new
all_payload = TestPayload.new
products_payload = TestPayload.new
product_payload = TestPayload.new
edit_payload = TestPayload.new
featured_payload = TestPayload.new
tree = Tree(TestPayload).new
tree.add "/", :root
tree.add "/*filepath", :all
tree.add "/products", :products
tree.add "/products/:id", :product
tree.add "/products/:id/edit", :edit
tree.add "/products/featured", :featured
tree.add "/", root_payload
tree.add "/*filepath", all_payload
tree.add "/products", products_payload
tree.add "/products/:id", product_payload
tree.add "/products/:id/edit", edit_payload
tree.add "/products/featured", featured_payload
# / (:all)
# +-products (:products)
@ -195,9 +224,9 @@ module Radix
it "does not split named parameters across shared key" do
tree = Tree(TestPayload).new
tree.add "/", :root
tree.add "/:category", :category
tree.add "/:category/:subcategory", :subcategory
tree.add "/", TestPayload.new
tree.add "/:category", TestPayload.new
tree.add "/:category/:subcategory", TestPayload.new
# / (:root)
# +-:category (:category)
@ -212,11 +241,11 @@ module Radix
it "does not allow different named parameters sharing same level" do
tree = Tree(TestPayload).new
tree.add "/", :root
tree.add "/:post", :post
tree.add "/", TestPayload.new
tree.add "/:post", TestPayload.new
expect_raises Tree::SharedKeyError do
tree.add "/:category/:post", :category_post
tree.add "/:category/:post", TestPayload.new
end
end
end
@ -226,26 +255,28 @@ module Radix
context "a single node" do
it "does not find when using different path" do
tree = Tree(TestPayload).new
tree.add "/about", :about
tree.add "/about", TestPayload.new
result = tree.find "/products"
result.found?.should be_false
end
it "finds when using matching path" do
about_payload = TestPayload.new
tree = Tree(TestPayload).new
tree.add "/about", :about
tree.add "/about", about_payload
result = tree.find "/about"
result.found?.should be_true
result.key.should eq("/about")
result.payload?.should be_truthy
result.payload.should eq(:about)
result.payload.should eq(about_payload)
end
it "finds when using path with trailing slash" do
about_payload = TestPayload.new
tree = Tree(TestPayload).new
tree.add "/about", :about
tree.add "/about", about_payload
result = tree.find "/about/"
result.found?.should be_true
@ -253,62 +284,78 @@ module Radix
end
it "finds when key has trailing slash" do
about_payload = TestPayload.new
tree = Tree(TestPayload).new
tree.add "/about/", :about
tree.add "/about/", about_payload
result = tree.find "/about"
result.found?.should be_true
result.key.should eq("/about/")
result.payload.should eq(:about)
result.payload.should eq(about_payload)
end
end
context "nodes with shared parent" do
it "finds matching path" do
root_payload = TestPayload.new
abc_payload = TestPayload.new
axyz_payload = TestPayload.new
tree = Tree(TestPayload).new
tree.add "/", :root
tree.add "/abc", :abc
tree.add "/axyz", :axyz
tree.add "/", root_payload
tree.add "/abc", abc_payload
tree.add "/axyz", axyz_payload
result = tree.find("/abc")
result.found?.should be_true
result.key.should eq("/abc")
result.payload.should eq(:abc)
result.payload.should eq(abc_payload)
end
it "finds matching path across parents" do
root_payload = TestPayload.new
users_payload = TestPayload.new
products_payload = TestPayload.new
tags_payload = TestPayload.new
articles_payload = TestPayload.new
tree = Tree(TestPayload).new
tree.add "/", :root
tree.add "/admin/users", :users
tree.add "/admin/products", :products
tree.add "/blog/tags", :tags
tree.add "/blog/articles", :articles
tree.add "/", root_payload
tree.add "/admin/users", users_payload
tree.add "/admin/products", products_payload
tree.add "/blog/tags", tags_payload
tree.add "/blog/articles", articles_payload
result = tree.find("/blog/tags/")
result.found?.should be_true
result.key.should eq("/blog/tags")
result.payload.should eq(:tags)
result.payload.should eq(tags_payload)
end
end
context "dealing with catch all" do
it "finds matching path" do
root_payload = TestPayload.new
all_payload = TestPayload.new
about_payload = TestPayload.new
tree = Tree(TestPayload).new
tree.add "/", :root
tree.add "/*filepath", :all
tree.add "/about", :about
tree.add "/", root_payload
tree.add "/*filepath", all_payload
tree.add "/about", about_payload
result = tree.find("/src/file.png")
result.found?.should be_true
result.key.should eq("/*filepath")
result.payload.should eq(:all)
result.payload.should eq(all_payload)
end
it "returns catch all in parameters" do
root_payload = TestPayload.new
all_payload = TestPayload.new
about_payload = TestPayload.new
tree = Tree(TestPayload).new
tree.add "/", :root
tree.add "/*filepath", :all
tree.add "/about", :about
tree.add "/", root_payload
tree.add "/*filepath", all_payload
tree.add "/about", about_payload
result = tree.find("/src/file.png")
result.found?.should be_true
@ -317,9 +364,11 @@ module Radix
end
it "returns optional catch all" do
root_payload = TestPayload.new
extra_payload = TestPayload.new
tree = Tree(TestPayload).new
tree.add "/", :root
tree.add "/search/*extra", :extra
tree.add "/", root_payload
tree.add "/search/*extra", extra_payload
result = tree.find("/search")
result.found?.should be_true
@ -329,9 +378,11 @@ module Radix
end
it "does not find when catch all is not full match" do
root_payload = TestPayload.new
search_payload = TestPayload.new
tree = Tree(TestPayload).new
tree.add "/", :root
tree.add "/search/public/*query", :search
tree.add "/", root_payload
tree.add "/search/public/*query", search_payload
result = tree.find("/search")
result.found?.should be_false
@ -340,34 +391,45 @@ module Radix
context "dealing with named parameters" do
it "finds matching path" do
root_payload = TestPayload.new
products_payload = TestPayload.new
product_payload = TestPayload.new
edit_payload = TestPayload.new
tree = Tree(TestPayload).new
tree.add "/", :root
tree.add "/products", :products
tree.add "/products/:id", :product
tree.add "/products/:id/edit", :edit
tree.add "/", root_payload
tree.add "/products", products_payload
tree.add "/products/:id", product_payload
tree.add "/products/:id/edit", edit_payload
result = tree.find("/products/10")
result.found?.should be_true
result.key.should eq("/products/:id")
result.payload.should eq(:product)
result.payload.should eq(product_payload)
end
it "does not find partial matching path" do
root_payload = TestPayload.new
products_payload = TestPayload.new
edit_payload = TestPayload.new
tree = Tree(TestPayload).new
tree.add "/", :root
tree.add "/products", :products
tree.add "/products/:id/edit", :edit
tree.add "/", root_payload
tree.add "/products", products_payload
tree.add "/products/:id/edit", edit_payload
result = tree.find("/products/10")
result.found?.should be_false
end
it "returns named parameters in result" do
root_payload = TestPayload.new
products_payload = TestPayload.new
product_payload = TestPayload.new
edit_payload = TestPayload.new
tree = Tree(TestPayload).new
tree.add "/", :root
tree.add "/products", :products
tree.add "/products/:id", :product
tree.add "/products/:id/edit", :edit
tree.add "/", root_payload
tree.add "/products", products_payload
tree.add "/products/:id", product_payload
tree.add "/products/:id/edit", edit_payload
result = tree.find("/products/10/edit")
result.found?.should be_true
@ -376,10 +438,13 @@ module Radix
end
it "returns unicode values in parameters" do
root_payload = TestPayload.new
language_payload = TestPayload.new
about_payload = TestPayload.new
tree = Tree(TestPayload).new
tree.add "/", :root
tree.add "/language/:name", :language
tree.add "/language/:name/about", :about
tree.add "/", root_payload
tree.add "/language/:name", language_payload
tree.add "/language/:name/about", about_payload
result = tree.find("/language/日本語")
result.found?.should be_true
@ -390,20 +455,24 @@ module Radix
context "dealing with multiple named parameters" do
it "finds matching path" do
root_payload = TestPayload.new
static_page_payload = TestPayload.new
tree = Tree(TestPayload).new
tree.add "/", :root
tree.add "/:section/:page", :static_page
tree.add "/", root_payload
tree.add "/:section/:page", static_page_payload
result = tree.find("/about/shipping")
result.found?.should be_true
result.key.should eq("/:section/:page")
result.payload.should eq(:static_page)
result.payload.should eq(static_page_payload)
end
it "returns named parameters in result" do
root_payload = TestPayload.new
static_page_payload = TestPayload.new
tree = Tree(TestPayload).new
tree.add "/", :root
tree.add "/:section/:page", :static_page
tree.add "/", root_payload
tree.add "/:section/:page", static_page_payload
result = tree.find("/about/shipping")
result.found?.should be_true
@ -418,18 +487,24 @@ module Radix
context "dealing with both catch all and named parameters" do
it "finds matching path" do
root_payload = TestPayload.new
all_payload = TestPayload.new
products_payload = TestPayload.new
product_payload = TestPayload.new
edit_payload = TestPayload.new
featured_payload = TestPayload.new
tree = Tree(TestPayload).new
tree.add "/", :root
tree.add "/*filepath", :all
tree.add "/products", :products
tree.add "/products/:id", :product
tree.add "/products/:id/edit", :edit
tree.add "/products/featured", :featured
tree.add "/", root_payload
tree.add "/*filepath", all_payload
tree.add "/products", products_payload
tree.add "/products/:id", product_payload
tree.add "/products/:id/edit", edit_payload
tree.add "/products/featured", featured_payload
result = tree.find("/products/1000")
result.found?.should be_true
result.key.should eq("/products/:id")
result.payload.should eq(:product)
result.payload.should eq(product_payload)
result = tree.find("/admin/articles")
result.found?.should be_true
@ -439,7 +514,7 @@ module Radix
result = tree.find("/products/featured")
result.found?.should be_true
result.key.should eq("/products/featured")
result.payload.should eq(:featured)
result.payload.should eq(featured_payload)
end
end
end

View file

@ -29,7 +29,7 @@ module Radix
class Node(T)
getter :key
getter? :placeholder
property! payload : T
property! payload : T?
property :children
# Returns the priority of the Node based on it's *key*
@ -61,7 +61,7 @@ module Radix
#
# - *key* - A `String` that represents this node.
# - *payload* - An Optional payload for this node.
def initialize(@key : String, @payload : T = nil, @placeholder = false)
def initialize(@key : String, @payload, @placeholder = false)
@children = [] of Node(T)
@priority = compute_priority
end

View file

@ -20,13 +20,20 @@ module Radix
end
end
# :nodoc:
class SharedKeyError < Exception
def initialize(new_key, existing_key)
super("Tried to place key '#{new_key}' at same level as '#{existing_key}'")
end
end
# Returns the root `Node` element of the Tree.
#
# On a new tree instance, this will be a placeholder.
getter root : Node(T)
def initialize
@root = Node(T).new("", placeholder: true)
@root = Node(T).new("", nil, placeholder: true)
end
# Inserts given *path* into the Tree
@ -103,7 +110,7 @@ module Radix
end
# :nodoc:
private def add(path : String, payload, node : Node)
private def add(path : String, payload, node : Node(T))
key_reader = Char::Reader.new(node.key)
path_reader = Char::Reader.new(path)