aboutsummaryrefslogblamecommitdiffstats
path: root/actionpack/test/journey/path/pattern_test.rb
blob: 77c19369b03b4c32580dd36e493d93c96604c2e0 (plain) (tree)
1
2
3
4
5
6
7
8
9
10

                             
                       



                     
                                                 

                                         

                










                                                                                          
                                  
                                                                    
                                 
                   
                                   
                         
                  
             




                                                  










                                                                                                   
                                  
                                                                                 
                                 
                   
                                   
                         
                   
             




                                                  









                                                                       
                                  
                                                                
                                 
                   
                                   
                         
                  
             




                                              
                               
                          
                     



                          
                       
                
           


                                               



                               


                                                        
                                   
                                              




                                                            
                               
                     
                            
                       
                
           

                                    


                                     
                               
                          
                                      
                       
                
           


                                               


                                             
                                                              
                               
                                 
                         
                       
                

           







                                                               
                               
                          
                                      
                       
                
           

                                           



                                            
                               
                              
                                            
                       
                
           


                                              





                                                      
                               
                         
                       
                       
                
           



                                                            
                               
                                
                                       
                       
                
           


                                                   


                                      
                                                                    





                                             
                                                                   




                                                                     

                                                                             
 
                                


                                 

                                                                             


                                                                     
                                          





                                        

                                                                             


                                                                     

                                          




                                           

                                                                             


                                                                     


                                          



                              
                                                                       
 
                        






                                                       
                                                                       
 
                             

                                                       
                                       



                                                     
                                                                       
 
                                 

                                                       

                                       
           








                                                                       



         
# frozen_string_literal: true

require "abstract_unit"

module ActionDispatch
  module Journey
    module Path
      class TestPattern < ActiveSupport::TestCase
        SEPARATORS = ["/", ".", "?"].join

        x = /.+/
        {
          "/:controller(/:action)"       => %r{\A/(#{x})(?:/([^/.?]+))?\Z},
          "/:controller/foo"             => %r{\A/(#{x})/foo\Z},
          "/:controller/:action"         => %r{\A/(#{x})/([^/.?]+)\Z},
          "/:controller"                 => %r{\A/(#{x})\Z},
          "/:controller(/:action(/:id))" => %r{\A/(#{x})(?:/([^/.?]+)(?:/([^/.?]+))?)?\Z},
          "/:controller/:action.xml"     => %r{\A/(#{x})/([^/.?]+)\.xml\Z},
          "/:controller.:format"         => %r{\A/(#{x})\.([^/.?]+)\Z},
          "/:controller(.:format)"       => %r{\A/(#{x})(?:\.([^/.?]+))?\Z},
          "/:controller/*foo"            => %r{\A/(#{x})/(.+)\Z},
          "/:controller/*foo/bar"        => %r{\A/(#{x})/(.+)/bar\Z},
          "/:foo|*bar"                   => %r{\A/(?:([^/.?]+)|(.+))\Z},
        }.each do |path, expected|
          define_method(:"test_to_regexp_#{Regexp.escape(path)}") do
            path = Pattern.build(
              path,
              { controller: /.+/ },
              SEPARATORS,
              true
            )
            assert_equal(expected, path.to_regexp)
          end
        end

        {
          "/:controller(/:action)"       => %r{\A/(#{x})(?:/([^/.?]+))?(?:\b|\Z|/)},
          "/:controller/foo"             => %r{\A/(#{x})/foo(?:\b|\Z|/)},
          "/:controller/:action"         => %r{\A/(#{x})/([^/.?]+)(?:\b|\Z|/)},
          "/:controller"                 => %r{\A/(#{x})(?:\b|\Z|/)},
          "/:controller(/:action(/:id))" => %r{\A/(#{x})(?:/([^/.?]+)(?:/([^/.?]+))?)?(?:\b|\Z|/)},
          "/:controller/:action.xml"     => %r{\A/(#{x})/([^/.?]+)\.xml(?:\b|\Z|/)},
          "/:controller.:format"         => %r{\A/(#{x})\.([^/.?]+)(?:\b|\Z|/)},
          "/:controller(.:format)"       => %r{\A/(#{x})(?:\.([^/.?]+))?(?:\b|\Z|/)},
          "/:controller/*foo"            => %r{\A/(#{x})/(.+)(?:\b|\Z|/)},
          "/:controller/*foo/bar"        => %r{\A/(#{x})/(.+)/bar(?:\b|\Z|/)},
          "/:foo|*bar"                   => %r{\A/(?:([^/.?]+)|(.+))(?:\b|\Z|/)},
        }.each do |path, expected|
          define_method(:"test_to_non_anchored_regexp_#{Regexp.escape(path)}") do
            path = Pattern.build(
              path,
              { controller: /.+/ },
              SEPARATORS,
              false
            )
            assert_equal(expected, path.to_regexp)
          end
        end

        {
          "/:controller(/:action)"       => %w{ controller action },
          "/:controller/foo"             => %w{ controller },
          "/:controller/:action"         => %w{ controller action },
          "/:controller"                 => %w{ controller },
          "/:controller(/:action(/:id))" => %w{ controller action id },
          "/:controller/:action.xml"     => %w{ controller action },
          "/:controller.:format"         => %w{ controller format },
          "/:controller(.:format)"       => %w{ controller format },
          "/:controller/*foo"            => %w{ controller foo },
          "/:controller/*foo/bar"        => %w{ controller foo },
        }.each do |path, expected|
          define_method(:"test_names_#{Regexp.escape(path)}") do
            path = Pattern.build(
              path,
              { controller: /.+/ },
              SEPARATORS,
              true
            )
            assert_equal(expected, path.names)
          end
        end

        def test_to_regexp_with_extended_group
          path = Pattern.build(
            "/page/:name",
            { name: /
              #ROFL
              (tender|love
              #MAO
              )/x },
            SEPARATORS,
            true
          )
          assert_match(path, "/page/tender")
          assert_match(path, "/page/love")
          assert_no_match(path, "/page/loving")
        end

        def test_optional_names
          [
            ["/:foo(/:bar(/:baz))", %w{ bar baz }],
            ["/:foo(/:bar)", %w{ bar }],
            ["/:foo(/:bar)/:lol(/:baz)", %w{ bar baz }],
          ].each do |pattern, list|
            path = Pattern.from_string pattern
            assert_equal list.sort, path.optional_names.sort
          end
        end

        def test_to_regexp_match_non_optional
          path = Pattern.build(
            "/:name",
            { name: /\d+/ },
            SEPARATORS,
            true
          )
          assert_match(path, "/123")
          assert_no_match(path, "/")
        end

        def test_to_regexp_with_group
          path = Pattern.build(
            "/page/:name",
            { name: /(tender|love)/ },
            SEPARATORS,
            true
          )
          assert_match(path, "/page/tender")
          assert_match(path, "/page/love")
          assert_no_match(path, "/page/loving")
        end

        def test_ast_sets_regular_expressions
          requirements = { name: /(tender|love)/, value: /./ }
          path = Pattern.build(
            "/page/:name/:value",
            requirements,
            SEPARATORS,
            true
          )

          nodes = path.ast.grep(Nodes::Symbol)
          assert_equal 2, nodes.length
          nodes.each do |node|
            assert_equal requirements[node.to_sym], node.regexp
          end
        end

        def test_match_data_with_group
          path = Pattern.build(
            "/page/:name",
            { name: /(tender|love)/ },
            SEPARATORS,
            true
          )
          match = path.match "/page/tender"
          assert_equal "tender", match[1]
          assert_equal 2, match.length
        end

        def test_match_data_with_multi_group
          path = Pattern.build(
            "/page/:name/:id",
            { name: /t(((ender|love)))()/ },
            SEPARATORS,
            true
          )
          match = path.match "/page/tender/10"
          assert_equal "tender", match[1]
          assert_equal "10", match[2]
          assert_equal 3, match.length
          assert_equal %w{ tender 10 }, match.captures
        end

        def test_star_with_custom_re
          z = /\d+/
          path = Pattern.build(
            "/page/*foo",
            { foo: z },
            SEPARATORS,
            true
          )
          assert_equal(%r{\A/page/(#{z})\Z}, path.to_regexp)
        end

        def test_insensitive_regexp_with_group
          path = Pattern.build(
            "/page/:name/aaron",
            { name: /(tender|love)/i },
            SEPARATORS,
            true
          )
          assert_match(path, "/page/TENDER/aaron")
          assert_match(path, "/page/loVE/aaron")
          assert_no_match(path, "/page/loVE/AAron")
        end

        def test_to_regexp_with_strexp
          path = Pattern.build("/:controller", {}, SEPARATORS, true)
          x = %r{\A/([^/.?]+)\Z}

          assert_equal(x.source, path.source)
        end

        def test_to_regexp_defaults
          path = Pattern.from_string "/:controller(/:action(/:id))"
          expected = %r{\A/([^/.?]+)(?:/([^/.?]+)(?:/([^/.?]+))?)?\Z}
          assert_equal expected, path.to_regexp
        end

        def test_failed_match
          path = Pattern.from_string "/:controller(/:action(/:id(.:format)))"
          uri = "content"

          assert_not path =~ uri
        end

        def test_match_controller
          path = Pattern.from_string "/:controller(/:action(/:id(.:format)))"
          uri = "/content"

          match = path =~ uri
          assert_equal %w{ controller action id format }, match.names
          assert_equal "content", match[1]
          assert_nil match[2]
          assert_nil match[3]
          assert_nil match[4]
        end

        def test_match_controller_action
          path = Pattern.from_string "/:controller(/:action(/:id(.:format)))"
          uri = "/content/list"

          match = path =~ uri
          assert_equal %w{ controller action id format }, match.names
          assert_equal "content", match[1]
          assert_equal "list", match[2]
          assert_nil match[3]
          assert_nil match[4]
        end

        def test_match_controller_action_id
          path = Pattern.from_string "/:controller(/:action(/:id(.:format)))"
          uri = "/content/list/10"

          match = path =~ uri
          assert_equal %w{ controller action id format }, match.names
          assert_equal "content", match[1]
          assert_equal "list", match[2]
          assert_equal "10", match[3]
          assert_nil match[4]
        end

        def test_match_literal
          path = Path::Pattern.from_string "/books(/:action(.:format))"

          uri = "/books"
          match = path =~ uri
          assert_equal %w{ action format }, match.names
          assert_nil match[1]
          assert_nil match[2]
        end

        def test_match_literal_with_action
          path = Path::Pattern.from_string "/books(/:action(.:format))"

          uri = "/books/list"
          match = path =~ uri
          assert_equal %w{ action format }, match.names
          assert_equal "list", match[1]
          assert_nil match[2]
        end

        def test_match_literal_with_action_and_format
          path = Path::Pattern.from_string "/books(/:action(.:format))"

          uri = "/books/list.rss"
          match = path =~ uri
          assert_equal %w{ action format }, match.names
          assert_equal "list", match[1]
          assert_equal "rss", match[2]
        end

        def test_named_captures
          path = Path::Pattern.from_string "/books(/:action(.:format))"

          uri = "/books/list.rss"
          match = path =~ uri
          named_captures = { "action" => "list", "format" => "rss" }
          assert_equal named_captures, match.named_captures
        end
      end
    end
  end
end