Skip to content

Commit b774872

Browse files
committed
A baseline test for attribute matching.
It still needs the API to be tested against.
1 parent 4ef879e commit b774872

File tree

6 files changed

+154
-2
lines changed

6 files changed

+154
-2
lines changed

gix-attributes/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ serde1 = ["serde", "bstr/serde", "gix-glob/serde1"]
1818

1919
[dependencies]
2020
gix-features = { version = "^0.28.0", path = "../gix-features" }
21-
gix-path = { version = "^0.7.2", path = "../gix-path" }
21+
gix-path = { version = "^0.7.3", path = "../gix-path" }
2222
gix-quote = { version = "^0.4.3", path = "../gix-quote" }
2323
gix-glob = { version = "^0.5.5", path = "../gix-glob" }
2424

gix-attributes/src/name.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use bstr::BString;
1+
use bstr::{BStr, BString, ByteSlice};
22

33
use crate::{Name, NameRef};
44

@@ -20,6 +20,25 @@ impl AsRef<str> for NameRef<'_> {
2020
}
2121
}
2222

23+
impl<'a> TryFrom<&'a BStr> for NameRef<'a> {
24+
type Error = Error;
25+
26+
fn try_from(attr: &'a BStr) -> Result<Self, Self::Error> {
27+
fn attr_valid(attr: &BStr) -> bool {
28+
if attr.first() == Some(&b'-') {
29+
return false;
30+
}
31+
32+
attr.bytes()
33+
.all(|b| matches!(b, b'-' | b'.' | b'_' | b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9'))
34+
}
35+
36+
attr_valid(attr)
37+
.then(|| NameRef(attr.to_str().expect("no illformed utf8")))
38+
.ok_or_else(|| Error { attribute: attr.into() })
39+
}
40+
}
41+
2342
impl<'a> Name {
2443
/// Provide our ref-type.
2544
pub fn as_ref(&'a self) -> NameRef<'a> {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:3d5773248077311a5e1adf2db6930f87ec5e36a573caff2523d1a88957b7d2df
3+
size 11016
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#!/bin/bash
2+
set -eu -o pipefail
3+
4+
mkdir basics;
5+
6+
function baseline() {
7+
{
8+
echo "$1"
9+
git -c core.attributesFile=user.attributes check-attr -a "$1"
10+
echo
11+
} >> baseline
12+
}
13+
14+
15+
(cd basics
16+
git init
17+
18+
# based on https://github.com/git/git/blob/140b9478dad5d19543c1cb4fd293ccec228f1240/t/t0003-attributes.sh#L45
19+
mkdir -p a/b/d a/c b
20+
(
21+
echo "[attr]notest !test"
22+
echo "\" d \" test=d"
23+
echo " e test=e"
24+
echo " e\" test=e"
25+
echo "f test=f"
26+
echo "a/i test=a/i"
27+
echo "onoff test -test"
28+
echo "offon -test test"
29+
echo "no notest"
30+
echo "A/e/F test=A/e/F"
31+
) > .gitattributes
32+
(
33+
echo "g test=a/g"
34+
echo "b/g test=a/b/g"
35+
) > a/.gitattributes
36+
(
37+
echo "h test=a/b/h"
38+
echo "d/* test=a/b/d/*"
39+
echo "d/yes notest"
40+
) > a/b/.gitattributes
41+
(
42+
echo "global test=global"
43+
) > user.attributes
44+
45+
git add . && git commit -qm c1
46+
47+
baseline " d "
48+
baseline e
49+
baseline "e\""
50+
baseline a/i
51+
baseline onoff
52+
baseline offon
53+
baseline no
54+
baseline A/e/F
55+
baseline a/g
56+
baseline a/b/g
57+
baseline a/b/h
58+
baseline a/b/d/ANY
59+
baseline a/b/d/yes
60+
baseline global
61+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#[test]
2+
fn baseline() -> crate::Result {
3+
baseline::validate("basics")
4+
}
5+
6+
mod baseline {
7+
use bstr::{BStr, ByteSlice};
8+
use gix_attributes::StateRef;
9+
10+
pub fn validate(name: &str) -> crate::Result {
11+
let dir = gix_testtools::scripted_fixture_read_only("make_attributes_baseline.sh")?;
12+
let repo_dir = dir.join(name);
13+
let input = std::fs::read(repo_dir.join("baseline"))?;
14+
// TODO: everything with ignorecase (tolower, expect same results)
15+
16+
for (rela_path, attributes) in (Expectations { lines: input.lines() }) {
17+
dbg!(rela_path, attributes);
18+
}
19+
20+
Ok(())
21+
}
22+
23+
pub struct Expectations<'a> {
24+
pub lines: bstr::Lines<'a>,
25+
}
26+
27+
impl<'a> Iterator for Expectations<'a> {
28+
type Item = (
29+
&'a BStr,
30+
// Names might refer to attributes or macros
31+
Vec<(gix_attributes::NameRef<'a>, gix_attributes::StateRef<'a>)>,
32+
);
33+
34+
fn next(&mut self) -> Option<Self::Item> {
35+
let path = self.lines.next()?;
36+
let mut assignments = Vec::new();
37+
loop {
38+
let line = self.lines.next()?;
39+
if line.is_empty() {
40+
return Some((path.as_bstr(), assignments));
41+
}
42+
43+
let mut prev = None;
44+
let mut tokens = line.splitn(3, |b| {
45+
let is_match = *b == b' ' && prev.take() == Some(b':');
46+
prev = Some(*b);
47+
is_match
48+
});
49+
50+
if let Some(((_path, attr), info)) = tokens.next().zip(tokens.next()).zip(tokens.next()) {
51+
let state = match info {
52+
b"set" => StateRef::Set,
53+
b"unset" => StateRef::Unset,
54+
b"unspecified" => StateRef::Unspecified,
55+
_ => StateRef::Value(info.as_bstr()),
56+
};
57+
let attr = attr.trim_end_with(|b| b == ':');
58+
assignments.push((
59+
gix_attributes::NameRef::try_from(attr.as_bstr()).expect("valid attributes"),
60+
state,
61+
));
62+
} else {
63+
unreachable!("invalid line format: {line:?}", line = line.as_bstr())
64+
}
65+
}
66+
}
67+
}
68+
}
+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
mod attributes;
12
mod ignore;

0 commit comments

Comments
 (0)