| /* |
| * Copyright (C) 2010, Red Hat Inc. and others |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Distribution License v. 1.0 which is available at |
| * https://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: BSD-3-Clause |
| */ |
| package org.eclipse.jgit.attributes; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertTrue; |
| |
| import org.junit.Test; |
| |
| /** |
| * Tests git attributes pattern matches |
| */ |
| public class AttributesMatcherTest { |
| |
| @Test |
| public void testBasic() { |
| String pattern = "/test.stp"; |
| assertMatched(pattern, "/test.stp"); |
| |
| pattern = "#/test.stp"; |
| assertNotMatched(pattern, "/test.stp"); |
| } |
| |
| @Test |
| public void testFileNameWildcards() { |
| //Test basic * and ? for any pattern + any character |
| String pattern = "*.st?"; |
| assertMatched(pattern, "/test.stp"); |
| assertMatched(pattern, "/anothertest.stg"); |
| assertMatched(pattern, "/anothertest.st0"); |
| assertNotMatched(pattern, "/anothertest.sta1"); |
| //Check that asterisk does not expand to "/" |
| assertNotMatched(pattern, "/another/test.sta1"); |
| |
| //Same as above, with a leading slash to ensure that doesn't cause problems |
| pattern = "/*.st?"; |
| assertMatched(pattern, "/test.stp"); |
| assertMatched(pattern, "/anothertest.stg"); |
| assertMatched(pattern, "/anothertest.st0"); |
| assertNotMatched(pattern, "/anothertest.sta1"); |
| //Check that asterisk does not expand to "/" |
| assertNotMatched(pattern, "/another/test.sta1"); |
| |
| //Test for numbers |
| pattern = "*.sta[0-5]"; |
| assertMatched(pattern, "/test.sta5"); |
| assertMatched(pattern, "/test.sta4"); |
| assertMatched(pattern, "/test.sta3"); |
| assertMatched(pattern, "/test.sta2"); |
| assertMatched(pattern, "/test.sta1"); |
| assertMatched(pattern, "/test.sta0"); |
| assertMatched(pattern, "/anothertest.sta2"); |
| assertNotMatched(pattern, "test.stag"); |
| assertNotMatched(pattern, "test.sta6"); |
| |
| //Test for letters |
| pattern = "/[tv]est.sta[a-d]"; |
| assertMatched(pattern, "/test.staa"); |
| assertMatched(pattern, "/test.stab"); |
| assertMatched(pattern, "/test.stac"); |
| assertMatched(pattern, "/test.stad"); |
| assertMatched(pattern, "/vest.stac"); |
| assertNotMatched(pattern, "test.stae"); |
| assertNotMatched(pattern, "test.sta9"); |
| |
| //Test child directory/file is matched |
| pattern = "/src/ne?"; |
| assertMatched(pattern, "/src/new/"); |
| assertMatched(pattern, "/src/new"); |
| assertNotMatched(pattern, "/src/new/a.c"); |
| assertNotMatched(pattern, "/src/new/a/a.c"); |
| assertNotMatched(pattern, "/src/new.c"); |
| |
| //Test name-only fnmatcher matches |
| pattern = "ne?"; |
| assertMatched(pattern, "/src/new/"); |
| assertMatched(pattern, "/src/new"); |
| assertNotMatched(pattern, "/src/new/a.c"); |
| assertNotMatched(pattern, "/src/new/a/a.c"); |
| assertMatched(pattern, "/neb"); |
| assertNotMatched(pattern, "/src/new.c"); |
| } |
| |
| @Test |
| public void testTargetWithoutLeadingSlash() { |
| //Test basic * and ? for any pattern + any character |
| String pattern = "/*.st?"; |
| assertMatched(pattern, "test.stp"); |
| assertMatched(pattern, "anothertest.stg"); |
| assertMatched(pattern, "anothertest.st0"); |
| assertNotMatched(pattern, "anothertest.sta1"); |
| //Check that asterisk does not expand to "" |
| assertNotMatched(pattern, "another/test.sta1"); |
| |
| //Same as above, with a leading slash to ensure that doesn't cause problems |
| pattern = "/*.st?"; |
| assertMatched(pattern, "test.stp"); |
| assertMatched(pattern, "anothertest.stg"); |
| assertMatched(pattern, "anothertest.st0"); |
| assertNotMatched(pattern, "anothertest.sta1"); |
| //Check that asterisk does not expand to "" |
| assertNotMatched(pattern, "another/test.sta1"); |
| |
| //Test for numbers |
| pattern = "/*.sta[0-5]"; |
| assertMatched(pattern, "test.sta5"); |
| assertMatched(pattern, "test.sta4"); |
| assertMatched(pattern, "test.sta3"); |
| assertMatched(pattern, "test.sta2"); |
| assertMatched(pattern, "test.sta1"); |
| assertMatched(pattern, "test.sta0"); |
| assertMatched(pattern, "anothertest.sta2"); |
| assertNotMatched(pattern, "test.stag"); |
| assertNotMatched(pattern, "test.sta6"); |
| |
| //Test for letters |
| pattern = "/[tv]est.sta[a-d]"; |
| assertMatched(pattern, "test.staa"); |
| assertMatched(pattern, "test.stab"); |
| assertMatched(pattern, "test.stac"); |
| assertMatched(pattern, "test.stad"); |
| assertMatched(pattern, "vest.stac"); |
| assertNotMatched(pattern, "test.stae"); |
| assertNotMatched(pattern, "test.sta9"); |
| |
| //Test child directory/file is matched |
| pattern = "/src/ne?"; |
| assertMatched(pattern, "src/new/"); |
| assertMatched(pattern, "src/new"); |
| assertNotMatched(pattern, "src/new/a.c"); |
| assertNotMatched(pattern, "src/new/a/a.c"); |
| assertNotMatched(pattern, "src/new.c"); |
| |
| //Test name-only fnmatcher matches |
| pattern = "ne?"; |
| assertMatched(pattern, "src/new/"); |
| assertMatched(pattern, "src/new"); |
| assertNotMatched(pattern, "src/new/a.c"); |
| assertNotMatched(pattern, "src/new/a/a.c"); |
| assertMatched(pattern, "neb"); |
| assertNotMatched(pattern, "src/new.c"); |
| } |
| |
| @Test |
| public void testParentDirectoryGitAttributes() { |
| //Contains git attribute patterns such as might be seen in a parent directory |
| |
| //Test for wildcards |
| String pattern = "/*/*.c"; |
| assertMatched(pattern, "/file/a.c"); |
| assertMatched(pattern, "/src/a.c"); |
| assertNotMatched(pattern, "/src/new/a.c"); |
| |
| //Test child directory/file is matched |
| pattern = "/src/new"; |
| assertMatched(pattern, "/src/new/"); |
| assertMatched(pattern, "/src/new"); |
| assertNotMatched(pattern, "/src/new/a.c"); |
| assertNotMatched(pattern, "/src/new/a/a.c"); |
| assertNotMatched(pattern, "/src/new.c"); |
| |
| //Test child directory is matched, slash after name |
| pattern = "/src/new/"; |
| assertMatched(pattern, "/src/new/"); |
| assertNotMatched(pattern, "/src/new/a.c"); |
| assertNotMatched(pattern, "/src/new/a/a.c"); |
| assertNotMatched(pattern, "/src/new"); |
| assertNotMatched(pattern, "/src/new.c"); |
| |
| //Test directory is matched by name only |
| pattern = "b1"; |
| assertNotMatched(pattern, "/src/new/a/b1/a.c"); |
| assertNotMatched(pattern, "/src/new/a/b2/file.c"); |
| assertNotMatched(pattern, "/src/new/a/bb1/file.c"); |
| assertNotMatched(pattern, "/src/new/a/file.c"); |
| assertNotMatched(pattern, "/src/new/a/bb1"); |
| assertMatched(pattern, "/src/new/a/b1"); |
| } |
| |
| @Test |
| public void testTrailingSlash() { |
| String pattern = "/src/"; |
| assertMatched(pattern, "/src/"); |
| assertNotMatched(pattern, "/src/new"); |
| assertNotMatched(pattern, "/src/new/a.c"); |
| assertNotMatched(pattern, "/src/a.c"); |
| assertNotMatched(pattern, "/src"); |
| assertNotMatched(pattern, "/srcA/"); |
| |
| pattern = "src/"; |
| assertMatched(pattern, "src/"); |
| assertMatched(pattern, "/src/"); |
| assertNotMatched(pattern, "src"); |
| assertNotMatched(pattern, "/src/new"); |
| assertNotMatched(pattern, "/src/new/a.c"); |
| assertNotMatched(pattern, "/src/a.c"); |
| assertNotMatched(pattern, "foo/src/a.c"); |
| assertNotMatched(pattern, "foo/src/bar/a.c"); |
| assertNotMatched(pattern, "foo/src/bar/src"); |
| assertMatched(pattern, "foo/src/"); |
| assertMatched(pattern, "foo/src/bar/src/"); |
| } |
| |
| @Test |
| public void testNameOnlyMatches() { |
| /* |
| * Name-only matches do not contain any path separators |
| */ |
| //Test matches for file extension |
| String pattern = "*.stp"; |
| assertMatched(pattern, "/test.stp"); |
| assertMatched(pattern, "/src/test.stp"); |
| assertNotMatched(pattern, "/test.stp1"); |
| assertNotMatched(pattern, "/test.astp"); |
| assertNotMatched(pattern, "test.stp/foo.bar"); |
| assertMatched(pattern, "test.stp"); |
| assertMatched(pattern, "test.stp/"); |
| assertMatched(pattern, "test.stp/test.stp"); |
| |
| //Test matches for name-only, applies to file name or folder name |
| pattern = "src"; |
| assertMatched(pattern, "/src"); |
| assertMatched(pattern, "/src/"); |
| assertNotMatched(pattern, "/src/a.c"); |
| assertNotMatched(pattern, "/src/new/a.c"); |
| assertNotMatched(pattern, "/new/src/a.c"); |
| assertMatched(pattern, "/file/src"); |
| |
| //Test matches for name-only, applies only to folder names |
| pattern = "src/"; |
| assertNotMatched(pattern, "/src/a.c"); |
| assertNotMatched(pattern, "/src/new/a.c"); |
| assertNotMatched(pattern, "/new/src/a.c"); |
| assertNotMatched(pattern, "/src"); |
| assertNotMatched(pattern, "/file/src"); |
| assertMatched(pattern, "/file/src/"); |
| |
| //Test matches for name-only, applies to file name or folder name |
| //With a small wildcard |
| pattern = "?rc"; |
| assertNotMatched(pattern, "/src/a.c"); |
| assertNotMatched(pattern, "/src/new/a.c"); |
| assertNotMatched(pattern, "/new/src/a.c"); |
| assertMatched(pattern, "/new/src/"); |
| assertMatched(pattern, "/file/src"); |
| assertMatched(pattern, "/src/"); |
| |
| //Test matches for name-only, applies to file name or folder name |
| //With a small wildcard |
| pattern = "?r[a-c]"; |
| assertNotMatched(pattern, "/src/a.c"); |
| assertNotMatched(pattern, "/src/new/a.c"); |
| assertNotMatched(pattern, "/new/src/a.c"); |
| assertMatched(pattern, "/file/src"); |
| assertMatched(pattern, "/src/"); |
| assertNotMatched(pattern, "/srb/a.c"); |
| assertNotMatched(pattern, "/grb/new/a.c"); |
| assertNotMatched(pattern, "/new/crb/a.c"); |
| assertMatched(pattern, "/file/3rb"); |
| assertMatched(pattern, "/xrb/"); |
| assertNotMatched(pattern, "/3ra/a.c"); |
| assertNotMatched(pattern, "/5ra/new/a.c"); |
| assertNotMatched(pattern, "/new/1ra/a.c"); |
| assertNotMatched(pattern, "/new/1ra/a.c/"); |
| assertMatched(pattern, "/file/dra"); |
| assertMatched(pattern, "/file/dra/"); |
| assertMatched(pattern, "/era/"); |
| assertNotMatched(pattern, "/crg"); |
| assertNotMatched(pattern, "/cr3"); |
| } |
| |
| @Test |
| public void testGetters() { |
| AttributesRule r = new AttributesRule("/pattern/", ""); |
| assertFalse(r.isNameOnly()); |
| assertTrue(r.isDirOnly()); |
| assertNotNull(r.getAttributes()); |
| assertTrue(r.getAttributes().isEmpty()); |
| assertEquals(r.getPattern(), "/pattern"); |
| |
| r = new AttributesRule("/patter?/", ""); |
| assertFalse(r.isNameOnly()); |
| assertTrue(r.isDirOnly()); |
| assertNotNull(r.getAttributes()); |
| assertTrue(r.getAttributes().isEmpty()); |
| assertEquals(r.getPattern(), "/patter?"); |
| |
| r = new AttributesRule("patt*", ""); |
| assertTrue(r.isNameOnly()); |
| assertFalse(r.isDirOnly()); |
| assertNotNull(r.getAttributes()); |
| assertTrue(r.getAttributes().isEmpty()); |
| assertEquals(r.getPattern(), "patt*"); |
| |
| r = new AttributesRule("pattern", "attribute1"); |
| assertTrue(r.isNameOnly()); |
| assertFalse(r.isDirOnly()); |
| assertNotNull(r.getAttributes()); |
| assertFalse(r.getAttributes().isEmpty()); |
| assertEquals(r.getAttributes().size(), 1); |
| assertEquals(r.getPattern(), "pattern"); |
| |
| r = new AttributesRule("pattern", "attribute1 -attribute2"); |
| assertTrue(r.isNameOnly()); |
| assertFalse(r.isDirOnly()); |
| assertNotNull(r.getAttributes()); |
| assertEquals(r.getAttributes().size(), 2); |
| assertEquals(r.getPattern(), "pattern"); |
| |
| r = new AttributesRule("pattern", "attribute1 \t-attribute2 \t"); |
| assertTrue(r.isNameOnly()); |
| assertFalse(r.isDirOnly()); |
| assertNotNull(r.getAttributes()); |
| assertEquals(r.getAttributes().size(), 2); |
| assertEquals(r.getPattern(), "pattern"); |
| |
| r = new AttributesRule("pattern", "attribute1\t-attribute2\t"); |
| assertTrue(r.isNameOnly()); |
| assertFalse(r.isDirOnly()); |
| assertNotNull(r.getAttributes()); |
| assertEquals(r.getAttributes().size(), 2); |
| assertEquals(r.getPattern(), "pattern"); |
| |
| r = new AttributesRule("pattern", "attribute1\t -attribute2\t "); |
| assertTrue(r.isNameOnly()); |
| assertFalse(r.isDirOnly()); |
| assertNotNull(r.getAttributes()); |
| assertEquals(r.getAttributes().size(), 2); |
| assertEquals(r.getPattern(), "pattern"); |
| |
| r = new AttributesRule("pattern", |
| "attribute1 -attribute2 attribute3=value "); |
| assertTrue(r.isNameOnly()); |
| assertFalse(r.isDirOnly()); |
| assertNotNull(r.getAttributes()); |
| assertEquals(r.getAttributes().size(), 3); |
| assertEquals(r.getPattern(), "pattern"); |
| assertEquals(r.getAttributes().get(0).toString(), "attribute1"); |
| assertEquals(r.getAttributes().get(1).toString(), "-attribute2"); |
| assertEquals(r.getAttributes().get(2).toString(), "attribute3=value"); |
| } |
| |
| @Test |
| public void testBracketsInGroup() { |
| //combinations of brackets in brackets, escaped and not |
| |
| String[] patterns = new String[]{"[[\\]]", "[\\[\\]]"}; |
| for (String pattern : patterns) { |
| assertNotMatched(pattern, ""); |
| assertNotMatched(pattern, "[]"); |
| assertNotMatched(pattern, "]["); |
| assertNotMatched(pattern, "[\\[]"); |
| assertNotMatched(pattern, "[[]"); |
| assertNotMatched(pattern, "[[]]"); |
| assertNotMatched(pattern, "[\\[\\]]"); |
| |
| assertMatched(pattern, "["); |
| assertMatched(pattern, "]"); |
| } |
| |
| patterns = new String[]{"[[]]", "[\\[]]"}; |
| for (String pattern : patterns) { |
| assertNotMatched(pattern, ""); |
| assertMatched(pattern, "[]"); |
| assertNotMatched(pattern, "]["); |
| assertNotMatched(pattern, "[\\[]"); |
| assertNotMatched(pattern, "[[]"); |
| assertNotMatched(pattern, "[[]]"); |
| assertNotMatched(pattern, "[\\[\\]]"); |
| |
| assertNotMatched(pattern, "["); |
| assertNotMatched(pattern, "]"); |
| } |
| } |
| |
| @Test |
| public void testFileNameWithLineTerminator() { |
| assertMatched("a?", "a\r"); |
| assertMatched("a?", "dir/a\r"); |
| assertMatched("*a", "\ra"); |
| assertMatched("dir/*a*", "dir/\ra\r"); |
| } |
| |
| /** |
| * Check for a match. If target ends with "/", match will assume that the |
| * target is meant to be a directory. |
| * |
| * @param pattern |
| * Pattern as it would appear in a .gitattributes file |
| * @param target |
| * Target file path relative to repository's GIT_DIR |
| */ |
| private void assertMatched(String pattern, String target) { |
| boolean value = match(pattern, target); |
| assertTrue("Expected a match for: " + pattern + " with: " + target, |
| value); |
| } |
| |
| /** |
| * Check for a match. If target ends with "/", match will assume that the |
| * target is meant to be a directory. |
| * |
| * @param pattern |
| * Pattern as it would appear in a .gitattributes file |
| * @param target |
| * Target file path relative to repository's GIT_DIR |
| */ |
| private void assertNotMatched(String pattern, String target) { |
| boolean value = match(pattern, target); |
| assertFalse("Expected no match for: " + pattern + " with: " + target, |
| value); |
| } |
| |
| /** |
| * Check for a match. If target ends with "/", match will assume that the |
| * target is meant to be a directory. |
| * |
| * @param pattern |
| * Pattern as it would appear in a .gitattributes file |
| * @param target |
| * Target file path relative to repository's GIT_DIR |
| * @return Result of {@link AttributesRule#isMatch(String, boolean)} |
| */ |
| private static boolean match(String pattern, String target) { |
| AttributesRule r = new AttributesRule(pattern, ""); |
| //If speed of this test is ever an issue, we can use a presetRule field |
| //to avoid recompiling a pattern each time. |
| return r.isMatch(target, target.endsWith("/")); |
| } |
| } |