require 'support' require 'mustermann/visualizer' describe Mustermann::Visualizer do subject(:highlight) { Mustermann::Visualizer.highlight(pattern) } before { Hansi.mode = 256 } after { Hansi.mode = nil } describe :highlight do context :sinatra do context "/a" do let(:pattern) { Mustermann.new("/a") } its(:to_ansi) { should be == "\e[0m\e[38;5;246m\e[38;5;246m\e[38;5;247m/\e[0m\e[38;5;246m\e[38;5;246m\e[38;5;246ma\e[0m" } its(:to_html) { should be == '/a' } its(:to_sexp) { should be == '(root (separator /) (char a))' } its(:to_pattern) { should be == pattern } its(:to_s) { should be == "/a" } its(:stylesheet) { should include(".mustermann_pattern .mustermann_illegal {\n color: #8b0000;") } example do highlight.to_html(css: false).should be == '/a' end example do renderer = Mustermann::Visualizer::Renderer::Generic result = highlight.render_with(renderer) result.should be == pattern.to_s end end context '/:name' do let(:pattern) { Mustermann.new("/:name") } its(:to_sexp) { should be == "(root (separator /) (capture : (name name)))" } end context '/{name}' do let(:pattern) { Mustermann.new("/{name}") } its(:to_sexp) { should be == "(root (separator /) (capture { (name name) }))" } end context '/{+name}' do let(:pattern) { Mustermann.new("/{+name}") } its(:to_sexp) { should be == "(root (separator /) (named_splat {+ (name name) }))" } end context ':user(@:host)?' do let(:pattern) { Mustermann.new(':user(@:host)?') } its(:to_sexp) { should be == '(root (capture : (name user)) (optional (group "(" (char @) (capture : (name host)) ")") ?))' } end context 'a b' do let(:pattern) { Mustermann.new('a b') } its(:to_sexp) { should be == '(root (char a) (char " ") (char b))' } end context '\:a' do let(:pattern) { Mustermann.new('\:a') } its(:to_sexp) { should be == '(root (escaped "\\\\" (escaped_char :)) (char a))' } end end context :regexp do context 'a' do let(:pattern) { Mustermann.new('a', type: :regexp) } its(:to_sexp) { should be == '(root (char a))' } end context '/(\d+)' do let(:pattern) { Mustermann.new('/(\d+)', type: :regexp) } its(:to_sexp) { should be == '(root (separator /) (capture "(" (special "\\\\d") (special +))))' } end context '\A' do let(:pattern) { Mustermann.new('\A', type: :regexp) } its(:to_sexp) { should be == '(root (illegal "\\\\A"))' } end context '(?.)\g' do let(:pattern) { Mustermann.new('(?.)\g', type: :regexp) } its(:to_sexp) { should be == '(root (capture "(?<" (name) >(special .))) (special "\\\\g"))' } end context '\p{Ll}' do let(:pattern) { Mustermann.new('\p{Ll}', type: :regexp) } its(:to_sexp) { should be == '(root (special "\\\\p{Ll}"))' } end context '\/' do let(:pattern) { Mustermann.new('\/', type: :regexp) } its(:to_sexp) { should be == '(root (separator /))' } end context '\[' do let(:pattern) { Mustermann.new('\[', type: :regexp) } its(:to_sexp) { should be == '(root (escaped "\\\\" (escaped_char [)))' } end context '^' do let(:pattern) { Mustermann.new('^', type: :regexp) } its(:to_sexp) { should be == '(root (illegal ^))' } end context '(?-mix:.)' do let(:pattern) { Mustermann.new('(?-mix:.)', type: :regexp) } its(:to_sexp) { should be == '(root (special "(") (special .) (special ")"))' } end context '[a\d]' do let(:pattern) { Mustermann.new('[a\d]', type: :regexp) } its(:to_sexp) { should be == '(root (special [) (char a) (special "\\\\d") (special ]))' } end context '[^a-z]' do let(:pattern) { Mustermann.new('[^a-z]', type: :regexp) } its(:to_sexp) { should be == '(root (special [) (special ^) (char a) (special -) (char z) (special ]))' } end context '[[:digit:]]' do let(:pattern) { Mustermann.new('[[:digit:]]', type: :regexp) } its(:to_sexp) { should be == '(root (special [[:digit:]]))' } end context 'a{1,}' do let(:pattern) { Mustermann.new('a{1,}', type: :regexp) } its(:to_sexp) { should be == "(root (char a) (special {1,}))" } end end context :template do context '/{name}' do let(:pattern) { Mustermann.new("/{+foo,bar*}", type: :template) } its(:to_sexp) { should be == "(root (separator /) (expression {+ (variable (name foo)) , (variable (name bar) *) }))" } end end context "custom AST based pattern" do let(:my_type) { Class.new(Mustermann::AST::Pattern) { on('x') { |*| node(:char, "o") } }} let(:pattern) { Mustermann.new("fxx", type: my_type) } its(:to_sexp) { should be == "(root (char f) (escaped x) (escaped x))" } end context "without known highlighter" do let(:pattern) { Mustermann::Pattern.new("foo") } its(:to_sexp) { should be == "(root (unknown foo))" } end end describe :tree do subject(:tree) { Mustermann::Visualizer.tree(pattern) } context :sinatra do context "/:a(@:b)" do let(:pattern) { Mustermann.new("/:a(@:b)") } let(:tree_data) do <<-TREE.gsub(/^\s+/, '') \e[38;5;61m\e[0m\e[38;5;100mroot\e[0m \e[0m\e[38;5;66m\"\e[0m\e[38;5;66m\e[38;5;242m\e[0m\e[38;5;66m\e[4m\e[38;5;100m/:a(@:b)\e[0m\e[38;5;66m\e[38;5;242m\e[0m\e[38;5;66m\" \e[0m \e[38;5;61m└ \e[0m\e[38;5;166mpayload\e[0m \e[38;5;61m ├ \e[0m\e[38;5;100mseparator\e[0m \e[0m\e[38;5;66m\"\e[0m\e[38;5;66m\e[38;5;242m\e[0m\e[38;5;66m\e[4m\e[38;5;100m/\e[0m\e[38;5;66m\e[38;5;242m:a(@:b)\e[0m\e[38;5;66m\" \e[0m \e[38;5;61m ├ \e[0m\e[38;5;100mcapture\e[0m \e[0m\e[38;5;66m\"\e[0m\e[38;5;66m\e[38;5;242m/\e[0m\e[38;5;66m\e[4m\e[38;5;100m:a\e[0m\e[38;5;66m\e[38;5;242m(@:b)\e[0m\e[38;5;66m\" \e[0m \e[38;5;61m └ \e[0m\e[38;5;100mgroup\e[0m \e[0m\e[38;5;66m\"\e[0m\e[38;5;66m\e[38;5;242m/:a\e[0m\e[38;5;66m\e[4m\e[38;5;100m(@:b)\e[0m\e[38;5;66m\e[38;5;242m\e[0m\e[38;5;66m\" \e[0m \e[38;5;61m └ \e[0m\e[38;5;166mpayload\e[0m \e[38;5;61m ├ \e[0m\e[38;5;100mchar\e[0m \e[0m\e[38;5;66m\"\e[0m\e[38;5;66m\e[38;5;242m/:a(\e[0m\e[38;5;66m\e[4m\e[38;5;100m@\e[0m\e[38;5;66m\e[38;5;242m:b)\e[0m\e[38;5;66m\" \e[0m \e[38;5;61m └ \e[0m\e[38;5;100mcapture\e[0m \e[0m\e[38;5;66m\"\e[0m\e[38;5;66m\e[38;5;242m/:a(@\e[0m\e[38;5;66m\e[4m\e[38;5;100m:b\e[0m\e[38;5;66m\e[38;5;242m)\e[0m\e[38;5;66m\" \e[0m TREE end its(:to_s) { should be == tree_data } end end context :shell do context "/**/*" do let(:pattern) { Mustermann.new("/**/*", type: :shell) } let(:tree_data) { "\e[38;5;61m\e[0m\e[38;5;100mpattern (not AST based)\e[0m \e[0m\e[38;5;66m\"\e[0m\e[38;5;66m\e[38;5;242m\e[0m\e[38;5;66m\e[4m\e[38;5;100m/**/*\e[0m\e[38;5;66m\e[38;5;242m\e[0m\e[38;5;66m\" \e[0m\n" } its(:to_s) { should be == tree_data } end end end end