aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes')
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributeNodeTest.java182
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributeTest.java77
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesMatcherTest.java412
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java296
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeWorkingTreeIteratorTest.java282
5 files changed, 1249 insertions, 0 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributeNodeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributeNodeTest.java
new file mode 100644
index 0000000000..ea250369a0
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributeNodeTest.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2014, Obeo.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.attributes;
+
+import static org.eclipse.jgit.attributes.Attribute.State.SET;
+import static org.eclipse.jgit.attributes.Attribute.State.UNSET;
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.junit.After;
+import org.junit.Test;
+
+/**
+ * Test {@link AttributesNode}
+ */
+public class AttributeNodeTest {
+
+ private static final Attribute A_SET_ATTR = new Attribute("A", SET);
+
+ private static final Attribute A_UNSET_ATTR = new Attribute("A", UNSET);
+
+ private static final Attribute B_SET_ATTR = new Attribute("B", SET);
+
+ private static final Attribute B_UNSET_ATTR = new Attribute("B", UNSET);
+
+ private static final Attribute C_VALUE_ATTR = new Attribute("C", "value");
+
+ private static final Attribute C_VALUE2_ATTR = new Attribute("C", "value2");
+
+ private InputStream is;
+
+ @After
+ public void after() throws IOException {
+ if (is != null)
+ is.close();
+ }
+
+ @Test
+ public void testBasic() throws IOException {
+ String attributeFileContent = "*.type1 A -B C=value\n"
+ + "*.type2 -A B C=value2";
+
+ is = new ByteArrayInputStream(attributeFileContent.getBytes());
+ AttributesNode node = new AttributesNode();
+ node.parse(is);
+ assertAttribute("file.type1", node,
+ asSet(A_SET_ATTR, B_UNSET_ATTR, C_VALUE_ATTR));
+ assertAttribute("file.type2", node,
+ asSet(A_UNSET_ATTR, B_SET_ATTR, C_VALUE2_ATTR));
+ }
+
+ @Test
+ public void testNegativePattern() throws IOException {
+ String attributeFileContent = "!*.type1 A -B C=value\n"
+ + "!*.type2 -A B C=value2";
+
+ is = new ByteArrayInputStream(attributeFileContent.getBytes());
+ AttributesNode node = new AttributesNode();
+ node.parse(is);
+ assertAttribute("file.type1", node, Collections.<Attribute> emptySet());
+ assertAttribute("file.type2", node, Collections.<Attribute> emptySet());
+ }
+
+ @Test
+ public void testEmptyNegativeAttributeKey() throws IOException {
+ String attributeFileContent = "*.type1 - \n" //
+ + "*.type2 - -A";
+ is = new ByteArrayInputStream(attributeFileContent.getBytes());
+ AttributesNode node = new AttributesNode();
+ node.parse(is);
+ assertAttribute("file.type1", node, Collections.<Attribute> emptySet());
+ assertAttribute("file.type2", node, asSet(A_UNSET_ATTR));
+ }
+
+ @Test
+ public void testEmptyValueKey() throws IOException {
+ String attributeFileContent = "*.type1 = \n" //
+ + "*.type2 =value\n"//
+ + "*.type3 attr=\n";
+ is = new ByteArrayInputStream(attributeFileContent.getBytes());
+ AttributesNode node = new AttributesNode();
+ node.parse(is);
+ assertAttribute("file.type1", node, Collections.<Attribute> emptySet());
+ assertAttribute("file.type2", node, Collections.<Attribute> emptySet());
+ assertAttribute("file.type3", node, asSet(new Attribute("attr", "")));
+ }
+
+ @Test
+ public void testEmptyLine() throws IOException {
+ String attributeFileContent = "*.type1 A -B C=value\n" //
+ + "\n" //
+ + " \n" //
+ + "*.type2 -A B C=value2";
+
+ is = new ByteArrayInputStream(attributeFileContent.getBytes());
+ AttributesNode node = new AttributesNode();
+ node.parse(is);
+ assertAttribute("file.type1", node,
+ asSet(A_SET_ATTR, B_UNSET_ATTR, C_VALUE_ATTR));
+ assertAttribute("file.type2", node,
+ asSet(A_UNSET_ATTR, B_SET_ATTR, C_VALUE2_ATTR));
+ }
+
+ @Test
+ public void testTabSeparator() throws IOException {
+ String attributeFileContent = "*.type1 \tA -B\tC=value\n"
+ + "*.type2\t -A\tB C=value2\n" //
+ + "*.type3 \t\t B\n" //
+ + "*.type3\t-A";//
+
+ is = new ByteArrayInputStream(attributeFileContent.getBytes());
+ AttributesNode node = new AttributesNode();
+ node.parse(is);
+ assertAttribute("file.type1", node,
+ asSet(A_SET_ATTR, B_UNSET_ATTR, C_VALUE_ATTR));
+ assertAttribute("file.type2", node,
+ asSet(A_UNSET_ATTR, B_SET_ATTR, C_VALUE2_ATTR));
+ assertAttribute("file.type3", node, asSet(A_UNSET_ATTR, B_SET_ATTR));
+ }
+
+ private void assertAttribute(String path, AttributesNode node,
+ Set<Attribute> attrs) {
+ HashMap<String, Attribute> attributes = new HashMap<String, Attribute>();
+ node.getAttributes(path, false, attributes);
+ assertEquals(attrs, new HashSet<Attribute>(attributes.values()));
+ }
+
+ static Set<Attribute> asSet(Attribute... attrs) {
+ Set<Attribute> result = new HashSet<Attribute>();
+ for (Attribute attr : attrs)
+ result.add(attr);
+ return result;
+ }
+
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributeTest.java
new file mode 100644
index 0000000000..93b954fa9a
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributeTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2010, Marc Strapetz <marc.strapetz@syntevo.com>
+ * Copyright (C) 2013, Gunnar Wagenknecht
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.attributes;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import org.eclipse.jgit.attributes.Attribute.State;
+import org.junit.Test;
+
+/**
+ * Tests {@link Attribute}
+ */
+public class AttributeTest {
+
+ @Test
+ public void testBasic() {
+ Attribute a = new Attribute("delta", State.SET);
+ assertEquals(a.getKey(), "delta");
+ assertEquals(a.getState(), State.SET);
+ assertNull(a.getValue());
+ assertEquals(a.toString(), "delta");
+
+ a = new Attribute("delta", State.UNSET);
+ assertEquals(a.getKey(), "delta");
+ assertEquals(a.getState(), State.UNSET);
+ assertNull(a.getValue());
+ assertEquals(a.toString(), "-delta");
+
+ a = new Attribute("delta", "value");
+ assertEquals(a.getKey(), "delta");
+ assertEquals(a.getState(), State.CUSTOM);
+ assertEquals(a.getValue(), "value");
+ assertEquals(a.toString(), "delta=value");
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesMatcherTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesMatcherTest.java
new file mode 100644
index 0000000000..6865406927
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesMatcherTest.java
@@ -0,0 +1,412 @@
+/*
+ * Copyright (C) 2010, Red Hat Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+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
+ * <p>
+ * Inspired by {@link org.eclipse.jgit.ignore.IgnoreMatcherTest}
+ * </p>
+ */
+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");
+ assertMatched(pattern, "/src/new/a.c");
+ assertMatched(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");
+ assertMatched(pattern, "/src/new/a.c");
+ assertMatched(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");
+ assertMatched(pattern, "src/new/a.c");
+ assertMatched(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");
+ assertMatched(pattern, "src/new/a.c");
+ assertMatched(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");
+ assertMatched(pattern, "/src/new/a.c");
+ assertMatched(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/");
+ assertMatched(pattern, "/src/new/a.c");
+ assertMatched(pattern, "/src/new/a/a.c");
+ assertNotMatched(pattern, "/src/new");
+ assertNotMatched(pattern, "/src/new.c");
+
+ //Test directory is matched by name only
+ pattern = "b1";
+ assertMatched(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");
+ }
+
+ @Test
+ public void testTrailingSlash() {
+ String pattern = "/src/";
+ assertMatched(pattern, "/src/");
+ assertMatched(pattern, "/src/new");
+ assertMatched(pattern, "/src/new/a.c");
+ assertMatched(pattern, "/src/a.c");
+ assertNotMatched(pattern, "/src");
+ assertNotMatched(pattern, "/srcA/");
+ }
+
+ @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");
+
+ //Test matches for name-only, applies to file name or folder name
+ pattern = "src";
+ assertMatched(pattern, "/src");
+ assertMatched(pattern, "/src/");
+ assertMatched(pattern, "/src/a.c");
+ assertMatched(pattern, "/src/new/a.c");
+ assertMatched(pattern, "/new/src/a.c");
+ assertMatched(pattern, "/file/src");
+
+ //Test matches for name-only, applies only to folder names
+ pattern = "src/";
+ assertMatched(pattern, "/src/");
+ assertMatched(pattern, "/src/a.c");
+ assertMatched(pattern, "/src/new/a.c");
+ assertMatched(pattern, "/new/src/a.c");
+ assertNotMatched(pattern, "/src");
+ assertNotMatched(pattern, "/file/src");
+
+ //Test matches for name-only, applies to file name or folder name
+ //With a small wildcard
+ pattern = "?rc";
+ assertMatched(pattern, "/src/a.c");
+ assertMatched(pattern, "/src/new/a.c");
+ assertMatched(pattern, "/new/src/a.c");
+ 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]";
+ assertMatched(pattern, "/src/a.c");
+ assertMatched(pattern, "/src/new/a.c");
+ assertMatched(pattern, "/new/src/a.c");
+ assertMatched(pattern, "/file/src");
+ assertMatched(pattern, "/src/");
+ assertMatched(pattern, "/srb/a.c");
+ assertMatched(pattern, "/grb/new/a.c");
+ assertMatched(pattern, "/new/crb/a.c");
+ assertMatched(pattern, "/file/3rb");
+ assertMatched(pattern, "/xrb/");
+ assertMatched(pattern, "/3ra/a.c");
+ assertMatched(pattern, "/5ra/new/a.c");
+ assertMatched(pattern, "/new/1ra/a.c");
+ 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.dirOnly());
+ assertNotNull(r.getAttributes());
+ assertTrue(r.getAttributes().isEmpty());
+ assertEquals(r.getPattern(), "/pattern");
+
+ r = new AttributesRule("/patter?/", "");
+ assertFalse(r.isNameOnly());
+ assertTrue(r.dirOnly());
+ assertNotNull(r.getAttributes());
+ assertTrue(r.getAttributes().isEmpty());
+ assertEquals(r.getPattern(), "/patter?");
+
+ r = new AttributesRule("patt*", "");
+ assertTrue(r.isNameOnly());
+ assertFalse(r.dirOnly());
+ assertNotNull(r.getAttributes());
+ assertTrue(r.getAttributes().isEmpty());
+ assertEquals(r.getPattern(), "patt*");
+
+ r = new AttributesRule("pattern", "attribute1");
+ assertTrue(r.isNameOnly());
+ assertFalse(r.dirOnly());
+ 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.dirOnly());
+ 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.dirOnly());
+ 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.dirOnly());
+ 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.dirOnly());
+ 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.dirOnly());
+ 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");
+ }
+
+ /**
+ * 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
+ */
+ public 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
+ */
+ public 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("/"));
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java
new file mode 100644
index 0000000000..49279e6e5a
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2010, Red Hat Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.attributes;
+
+import static java.util.Arrays.asList;
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.hamcrest.MatcherAssert.assertThat;
+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 java.io.IOException;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.attributes.Attribute.State;
+import org.eclipse.jgit.dircache.DirCacheIterator;
+import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests attributes node behavior on the the index.
+ */
+public class AttributesNodeDirCacheIteratorTest extends RepositoryTestCase {
+
+ private static final FileMode D = FileMode.TREE;
+
+ private static final FileMode F = FileMode.REGULAR_FILE;
+
+ private static Attribute EOL_LF = new Attribute("eol", "lf");
+
+ private static Attribute DELTA_UNSET = new Attribute("delta", State.UNSET);
+
+ private Git git;
+
+ private TreeWalk walk;
+
+ @Override
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ git = new Git(db);
+
+ }
+
+ @Test
+ public void testRules() throws Exception {
+ writeAttributesFile(".git/info/attributes", "windows* eol=crlf");
+
+ writeAttributesFile(".gitattributes", "*.txt eol=lf");
+ writeTrashFile("windows.file", "");
+ writeTrashFile("windows.txt", "");
+ writeTrashFile("readme.txt", "");
+
+ writeAttributesFile("src/config/.gitattributes", "*.txt -delta");
+ writeTrashFile("src/config/readme.txt", "");
+ writeTrashFile("src/config/windows.file", "");
+ writeTrashFile("src/config/windows.txt", "");
+
+ // Adds file to index
+ git.add().addFilepattern(".").call();
+
+ walk = beginWalk();
+
+ assertIteration(F, ".gitattributes");
+ assertIteration(F, "readme.txt", asList(EOL_LF));
+
+ assertIteration(D, "src");
+
+ assertIteration(D, "src/config");
+ assertIteration(F, "src/config/.gitattributes");
+ assertIteration(F, "src/config/readme.txt", asList(DELTA_UNSET));
+ assertIteration(F, "src/config/windows.file", null);
+ assertIteration(F, "src/config/windows.txt", asList(DELTA_UNSET));
+
+ assertIteration(F, "windows.file", null);
+ assertIteration(F, "windows.txt", asList(EOL_LF));
+
+ endWalk();
+ }
+
+ /**
+ * Checks that if there is no .gitattributes file in the repository
+ * everything still work fine.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testNoAttributes() throws Exception {
+ writeTrashFile("l0.txt", "");
+ writeTrashFile("level1/l1.txt", "");
+ writeTrashFile("level1/level2/l2.txt", "");
+
+ // Adds file to index
+ git.add().addFilepattern(".").call();
+ walk = beginWalk();
+
+ assertIteration(F, "l0.txt");
+
+ assertIteration(D, "level1");
+ assertIteration(F, "level1/l1.txt");
+
+ assertIteration(D, "level1/level2");
+ assertIteration(F, "level1/level2/l2.txt");
+
+ endWalk();
+ }
+
+ /**
+ * Checks that empty .gitattribute files do not return incorrect value.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testEmptyGitAttributeFile() throws Exception {
+ writeAttributesFile(".git/info/attributes", "");
+ writeTrashFile("l0.txt", "");
+ writeAttributesFile(".gitattributes", "");
+ writeTrashFile("level1/l1.txt", "");
+ writeTrashFile("level1/level2/l2.txt", "");
+
+ // Adds file to index
+ git.add().addFilepattern(".").call();
+ walk = beginWalk();
+
+ assertIteration(F, ".gitattributes");
+ assertIteration(F, "l0.txt");
+
+ assertIteration(D, "level1");
+ assertIteration(F, "level1/l1.txt");
+
+ assertIteration(D, "level1/level2");
+ assertIteration(F, "level1/level2/l2.txt");
+
+ endWalk();
+ }
+
+ @Test
+ public void testNoMatchingAttributes() throws Exception {
+ writeAttributesFile(".git/info/attributes", "*.java delta");
+ writeAttributesFile(".gitattributes", "*.java -delta");
+ writeAttributesFile("levelA/.gitattributes", "*.java eol=lf");
+ writeAttributesFile("levelB/.gitattributes", "*.txt eol=lf");
+
+ writeTrashFile("levelA/lA.txt", "");
+
+ // Adds file to index
+ git.add().addFilepattern(".").call();
+ walk = beginWalk();
+
+ assertIteration(F, ".gitattributes");
+
+ assertIteration(D, "levelA");
+ assertIteration(F, "levelA/.gitattributes");
+ assertIteration(F, "levelA/lA.txt");
+
+ assertIteration(D, "levelB");
+ assertIteration(F, "levelB/.gitattributes");
+
+ endWalk();
+ }
+
+ @Test
+ public void testIncorrectAttributeFileName() throws Exception {
+ writeAttributesFile("levelA/file.gitattributes", "*.txt -delta");
+ writeAttributesFile("gitattributes", "*.txt eol=lf");
+
+ writeTrashFile("l0.txt", "");
+ writeTrashFile("levelA/lA.txt", "");
+
+ // Adds file to index
+ git.add().addFilepattern(".").call();
+ walk = beginWalk();
+
+ assertIteration(F, "gitattributes");
+
+ assertIteration(F, "l0.txt");
+
+ assertIteration(D, "levelA");
+ assertIteration(F, "levelA/file.gitattributes");
+ assertIteration(F, "levelA/lA.txt");
+
+ endWalk();
+ }
+
+ private void assertIteration(FileMode type, String pathName)
+ throws IOException {
+ assertIteration(type, pathName, Collections.<Attribute> emptyList());
+ }
+
+ private void assertIteration(FileMode type, String pathName,
+ List<Attribute> nodeAttrs) throws IOException {
+ assertTrue("walk has entry", walk.next());
+ assertEquals(pathName, walk.getPathString());
+ assertEquals(type, walk.getFileMode(0));
+ DirCacheIterator itr = walk.getTree(0, DirCacheIterator.class);
+ assertNotNull("has tree", itr);
+
+ AttributesNode attributeNode = itr.getEntryAttributesNode(db
+ .newObjectReader());
+ assertAttributeNode(pathName, attributeNode, nodeAttrs);
+
+ if (D.equals(type))
+ walk.enterSubtree();
+
+ }
+
+ private void assertAttributeNode(String pathName,
+ AttributesNode attributeNode, List<Attribute> nodeAttrs) {
+ if (attributeNode == null)
+ assertTrue(nodeAttrs == null || nodeAttrs.isEmpty());
+ else {
+
+ Map<String, Attribute> entryAttributes = new LinkedHashMap<String, Attribute>();
+ attributeNode.getAttributes(pathName, false, entryAttributes);
+
+ if (nodeAttrs != null && !nodeAttrs.isEmpty()) {
+ for (Attribute attribute : nodeAttrs) {
+ assertThat(entryAttributes.values(), hasItem(attribute));
+ }
+ } else {
+ assertTrue(
+ "The entry "
+ + pathName
+ + " should not have any attributes. Instead, the following attributes are applied to this file "
+ + entryAttributes.toString(),
+ entryAttributes.isEmpty());
+ }
+ }
+ }
+
+ private void writeAttributesFile(String name, String... rules)
+ throws IOException {
+ StringBuilder data = new StringBuilder();
+ for (String line : rules)
+ data.append(line + "\n");
+ writeTrashFile(name, data.toString());
+ }
+
+ private TreeWalk beginWalk() throws Exception {
+ TreeWalk newWalk = new TreeWalk(db);
+ newWalk.addTree(new DirCacheIterator(db.readDirCache()));
+ return newWalk;
+ }
+
+ private void endWalk() throws IOException {
+ assertFalse("Not all files tested", walk.next());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeWorkingTreeIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeWorkingTreeIteratorTest.java
new file mode 100644
index 0000000000..64b0535d6a
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeWorkingTreeIteratorTest.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2014, Obeo.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.attributes;
+
+import static java.util.Arrays.asList;
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.hamcrest.MatcherAssert.assertThat;
+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 java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jgit.attributes.Attribute.State;
+import org.eclipse.jgit.errors.CorruptObjectException;
+import org.eclipse.jgit.junit.JGitTestUtil;
+import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.treewalk.FileTreeIterator;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.WorkingTreeIterator;
+import org.junit.Test;
+
+/**
+ * Tests attributes node behavior on the local filesystem.
+ */
+public class AttributesNodeWorkingTreeIteratorTest extends RepositoryTestCase {
+
+ private static final FileMode D = FileMode.TREE;
+
+ private static final FileMode F = FileMode.REGULAR_FILE;
+
+ private static Attribute EOL_CRLF = new Attribute("eol", "crlf");
+
+ private static Attribute EOL_LF = new Attribute("eol", "lf");
+
+ private static Attribute DELTA_UNSET = new Attribute("delta", State.UNSET);
+
+ private static Attribute CUSTOM_VALUE = new Attribute("custom", "value");
+
+ private TreeWalk walk;
+
+ @Test
+ public void testRules() throws Exception {
+
+ File customAttributeFile = File.createTempFile("tmp_",
+ "customAttributeFile", null);
+ customAttributeFile.deleteOnExit();
+
+ JGitTestUtil.write(customAttributeFile, "*.txt custom=value");
+ db.getConfig().setString("core", null, "attributesfile",
+ customAttributeFile.getAbsolutePath());
+ writeAttributesFile(".git/info/attributes", "windows* eol=crlf");
+
+ writeAttributesFile(".gitattributes", "*.txt eol=lf");
+ writeTrashFile("windows.file", "");
+ writeTrashFile("windows.txt", "");
+ writeTrashFile("global.txt", "");
+ writeTrashFile("readme.txt", "");
+
+ writeAttributesFile("src/config/.gitattributes", "*.txt -delta");
+ writeTrashFile("src/config/readme.txt", "");
+ writeTrashFile("src/config/windows.file", "");
+ writeTrashFile("src/config/windows.txt", "");
+
+ walk = beginWalk();
+
+ assertIteration(F, ".gitattributes");
+ assertIteration(F, "global.txt", asList(EOL_LF), null,
+ asList(CUSTOM_VALUE));
+ assertIteration(F, "readme.txt", asList(EOL_LF), null,
+ asList(CUSTOM_VALUE));
+
+ assertIteration(D, "src");
+
+ assertIteration(D, "src/config");
+ assertIteration(F, "src/config/.gitattributes");
+ assertIteration(F, "src/config/readme.txt", asList(DELTA_UNSET), null,
+ asList(CUSTOM_VALUE));
+ assertIteration(F, "src/config/windows.file", null, asList(EOL_CRLF),
+ null);
+ assertIteration(F, "src/config/windows.txt", asList(DELTA_UNSET),
+ asList(EOL_CRLF), asList(CUSTOM_VALUE));
+
+ assertIteration(F, "windows.file", null, asList(EOL_CRLF), null);
+ assertIteration(F, "windows.txt", asList(EOL_LF), asList(EOL_CRLF),
+ asList(CUSTOM_VALUE));
+
+ endWalk();
+ }
+
+ /**
+ * Checks that if there is no .gitattributes file in the repository
+ * everything still work fine.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testNoAttributes() throws Exception {
+ writeTrashFile("l0.txt", "");
+ writeTrashFile("level1/l1.txt", "");
+ writeTrashFile("level1/level2/l2.txt", "");
+
+ walk = beginWalk();
+
+ assertIteration(F, "l0.txt");
+
+ assertIteration(D, "level1");
+ assertIteration(F, "level1/l1.txt");
+
+ assertIteration(D, "level1/level2");
+ assertIteration(F, "level1/level2/l2.txt");
+
+ endWalk();
+ }
+
+ /**
+ * Checks that empty .gitattribute files do not return incorrect value.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testEmptyGitAttributeFile() throws Exception {
+ writeAttributesFile(".git/info/attributes", "");
+ writeTrashFile("l0.txt", "");
+ writeAttributesFile(".gitattributes", "");
+ writeTrashFile("level1/l1.txt", "");
+ writeTrashFile("level1/level2/l2.txt", "");
+
+ walk = beginWalk();
+
+ assertIteration(F, ".gitattributes");
+ assertIteration(F, "l0.txt");
+
+ assertIteration(D, "level1");
+ assertIteration(F, "level1/l1.txt");
+
+ assertIteration(D, "level1/level2");
+ assertIteration(F, "level1/level2/l2.txt");
+
+ endWalk();
+ }
+
+ @Test
+ public void testNoMatchingAttributes() throws Exception {
+ writeAttributesFile(".git/info/attributes", "*.java delta");
+ writeAttributesFile(".gitattributes", "*.java -delta");
+ writeAttributesFile("levelA/.gitattributes", "*.java eol=lf");
+ writeAttributesFile("levelB/.gitattributes", "*.txt eol=lf");
+
+ writeTrashFile("levelA/lA.txt", "");
+
+ walk = beginWalk();
+
+ assertIteration(F, ".gitattributes");
+
+ assertIteration(D, "levelA");
+ assertIteration(F, "levelA/.gitattributes");
+ assertIteration(F, "levelA/lA.txt");
+
+ assertIteration(D, "levelB");
+ assertIteration(F, "levelB/.gitattributes");
+
+ endWalk();
+ }
+
+ private void assertIteration(FileMode type, String pathName)
+ throws IOException {
+ assertIteration(type, pathName, Collections.<Attribute> emptyList(),
+ Collections.<Attribute> emptyList(),
+ Collections.<Attribute> emptyList());
+ }
+
+ private void assertIteration(FileMode type, String pathName,
+ List<Attribute> nodeAttrs, List<Attribute> infoAttrs,
+ List<Attribute> globalAttrs)
+ throws IOException {
+ assertTrue("walk has entry", walk.next());
+ assertEquals(pathName, walk.getPathString());
+ assertEquals(type, walk.getFileMode(0));
+ WorkingTreeIterator itr = walk.getTree(0, WorkingTreeIterator.class);
+ assertNotNull("has tree", itr);
+
+ AttributesNode attributeNode = itr.getEntryAttributesNode();
+ assertAttributeNode(pathName, attributeNode, nodeAttrs);
+ AttributesNode infoAttributeNode = itr.getInfoAttributesNode();
+ assertAttributeNode(pathName, infoAttributeNode, infoAttrs);
+ AttributesNode globalAttributeNode = itr.getGlobalAttributesNode();
+ assertAttributeNode(pathName, globalAttributeNode, globalAttrs);
+ if (D.equals(type))
+ walk.enterSubtree();
+
+ }
+
+ private void assertAttributeNode(String pathName,
+ AttributesNode attributeNode, List<Attribute> nodeAttrs) {
+ if (attributeNode == null)
+ assertTrue(nodeAttrs == null || nodeAttrs.isEmpty());
+ else {
+
+ Map<String, Attribute> entryAttributes = new LinkedHashMap<String, Attribute>();
+ attributeNode.getAttributes(pathName, false, entryAttributes);
+
+ if (nodeAttrs != null && !nodeAttrs.isEmpty()) {
+ for (Attribute attribute : nodeAttrs) {
+ assertThat(entryAttributes.values(), hasItem(attribute));
+ }
+ } else {
+ assertTrue(
+ "The entry "
+ + pathName
+ + " should not have any attributes. Instead, the following attributes are applied to this file "
+ + entryAttributes.toString(),
+ entryAttributes.isEmpty());
+ }
+ }
+ }
+
+ private void writeAttributesFile(String name, String... rules)
+ throws IOException {
+ StringBuilder data = new StringBuilder();
+ for (String line : rules)
+ data.append(line + "\n");
+ writeTrashFile(name, data.toString());
+ }
+
+ private TreeWalk beginWalk() throws CorruptObjectException {
+ TreeWalk newWalk = new TreeWalk(db);
+ newWalk.addTree(new FileTreeIterator(db));
+ return newWalk;
+ }
+
+ private void endWalk() throws IOException {
+ assertFalse("Not all files tested", walk.next());
+ }
+}