794 lines
21 KiB
Rust
794 lines
21 KiB
Rust
// Tests for ASG identifiers
|
|
//
|
|
// Copyright (C) 2014-2023 Ryan Specialty, LLC.
|
|
//
|
|
// This file is part of TAME.
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
use super::*;
|
|
use crate::{
|
|
num::Dim,
|
|
span::dummy::*,
|
|
sym::{GlobalSymbolIntern, SymbolId},
|
|
};
|
|
|
|
// Note that Ident has no variants capable of None
|
|
#[test]
|
|
fn ident_name() {
|
|
let name = "name".into();
|
|
let spair = SPair(name, S1);
|
|
|
|
assert_eq!(Some(spair), Ident::Missing(spair).name());
|
|
|
|
assert_eq!(
|
|
Some(spair),
|
|
Ident::Opaque(spair, IdentKind::Meta, Source::default()).name()
|
|
);
|
|
|
|
assert_eq!(
|
|
Some(spair),
|
|
Ident::Extern(spair, IdentKind::Meta, Source::default()).name()
|
|
);
|
|
|
|
assert_eq!(
|
|
Some(spair),
|
|
Ident::IdentFragment(
|
|
spair,
|
|
IdentKind::Meta,
|
|
Source::default(),
|
|
"".intern()
|
|
)
|
|
.name()
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn ident_kind() {
|
|
let name = SPair("foo".into(), S1);
|
|
let kind = IdentKind::Class(Dim::Matrix);
|
|
|
|
assert_eq!(None, Ident::Missing(name).kind());
|
|
|
|
assert_eq!(
|
|
Some(&kind),
|
|
Ident::Opaque(name, kind.clone(), Source::default()).kind()
|
|
);
|
|
|
|
assert_eq!(
|
|
Some(&kind),
|
|
Ident::Extern(name, kind.clone(), Source::default()).kind()
|
|
);
|
|
|
|
assert_eq!(
|
|
Some(&kind),
|
|
Ident::IdentFragment(
|
|
name,
|
|
kind.clone(),
|
|
Source::default(),
|
|
"".intern()
|
|
)
|
|
.kind()
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn ident_src() {
|
|
let name = SPair("foo".into(), S1);
|
|
let src = Source {
|
|
desc: Some("test source".into()),
|
|
..Default::default()
|
|
};
|
|
|
|
assert_eq!(None, Ident::Missing(name).src());
|
|
|
|
assert_eq!(
|
|
Some(&src),
|
|
Ident::Opaque(name, IdentKind::Meta, src.clone()).src()
|
|
);
|
|
|
|
assert_eq!(
|
|
None,
|
|
Ident::Extern(name, IdentKind::Meta, src.clone()).src()
|
|
);
|
|
|
|
assert_eq!(
|
|
Some(&src),
|
|
Ident::IdentFragment(name, IdentKind::Meta, src.clone(), "".intern())
|
|
.src()
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn ident_fragment() {
|
|
let name = SPair("foo".into(), S1);
|
|
let text = "foo".into();
|
|
|
|
assert_eq!(None, Ident::Missing(name).fragment());
|
|
|
|
assert_eq!(
|
|
None,
|
|
Ident::Opaque(name, IdentKind::Meta, Source::default()).fragment()
|
|
);
|
|
|
|
assert_eq!(
|
|
None,
|
|
Ident::Extern(name, IdentKind::Meta, Source::default()).fragment()
|
|
);
|
|
|
|
assert_eq!(
|
|
Some(text),
|
|
Ident::IdentFragment(name, IdentKind::Meta, Source::default(), text,)
|
|
.fragment()
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn ident_missing() {
|
|
let name = SPair("foo".into(), S1);
|
|
assert_eq!(Ident::Missing(name), Ident::declare(name));
|
|
}
|
|
|
|
#[test]
|
|
fn resolved_on_missing() {
|
|
let name = SPair("foo".into(), S1);
|
|
|
|
assert_eq!(
|
|
Ident::declare(name).resolved(),
|
|
Err(UnresolvedError::Missing(name))
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn ident_resolved() {
|
|
let sym = "foo".into();
|
|
let kind = IdentKind::Meta;
|
|
let src = Source {
|
|
desc: Some("ident ctor".into()),
|
|
..Default::default()
|
|
};
|
|
|
|
assert_eq!(
|
|
Ident::declare(SPair(sym, S1))
|
|
.resolve(S2, kind.clone(), src.clone())
|
|
.unwrap(),
|
|
Ident::Opaque(SPair(sym, S2), kind.clone(), src.clone()),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn resolved_on_ident() {
|
|
let sym = "ident resolve".into();
|
|
let kind = IdentKind::Meta;
|
|
let src = Source {
|
|
desc: Some("ident ctor".into()),
|
|
..Default::default()
|
|
};
|
|
|
|
assert_eq!(
|
|
Ident::declare(SPair(sym, S1))
|
|
.resolve(S2, kind.clone(), src.clone())
|
|
.unwrap()
|
|
.resolved()
|
|
.unwrap(),
|
|
(
|
|
&Ident::Opaque(SPair(sym, S2), kind.clone(), src.clone()),
|
|
SPair(sym, S2)
|
|
),
|
|
);
|
|
}
|
|
|
|
// Note that we don't care about similar sources. It's expected
|
|
// that the system populating the ASG will only resolve local
|
|
// symbols, and so redeclarations should represent that multiple
|
|
// packages have the same local symbol.
|
|
#[test]
|
|
fn ident_object_redeclare_same_src() {
|
|
let sym = "redecl".into();
|
|
let kind = IdentKind::Meta;
|
|
let src = Source::default();
|
|
|
|
let first = Ident::declare(SPair(sym, S1))
|
|
.resolve(S2, kind.clone(), src.clone())
|
|
.unwrap();
|
|
|
|
// Resolve twice, as if we encountered two local symbols.
|
|
assert_eq!(
|
|
first.clone().resolve(S3, kind.clone(), src.clone()),
|
|
Err((first, TransitionError::Redeclare(SPair(sym, S2), S3))),
|
|
);
|
|
}
|
|
|
|
mod extern_ {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn ident_object() {
|
|
let sym = "extern".into();
|
|
let kind = IdentKind::Class(Dim::Vector);
|
|
let src = Source {
|
|
desc: Some("extern".into()),
|
|
..Default::default()
|
|
};
|
|
|
|
assert_eq!(
|
|
Ident::declare(SPair(sym, S1)).extern_(
|
|
S2,
|
|
kind.clone(),
|
|
src.clone()
|
|
),
|
|
Ok(Ident::Extern(SPair(sym, S2), kind, src)),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn resolved_on_extern() {
|
|
let sym = "extern resolved".into();
|
|
let kind = IdentKind::Class(Dim::Vector);
|
|
let pkg_name: SymbolId = "pkg/name".intern();
|
|
let src = Source {
|
|
pkg_name: Some(pkg_name),
|
|
desc: Some("extern".into()),
|
|
..Default::default()
|
|
};
|
|
|
|
assert_eq!(
|
|
Ident::Extern(SPair(sym, S1), kind.clone(), src.clone()).resolved(),
|
|
Err(UnresolvedError::Extern(SPair(sym, S1), kind)),
|
|
);
|
|
}
|
|
|
|
// Extern first, then identifier
|
|
#[test]
|
|
fn redeclare_compatible_resolves() {
|
|
let sym = "extern_re_pre".into();
|
|
let kind = IdentKind::Class(Dim::Matrix);
|
|
let src = Source {
|
|
desc: Some("okay".into()),
|
|
..Default::default()
|
|
};
|
|
|
|
// Compatible kind, should resolve.
|
|
let result = Ident::declare(SPair(sym, S1))
|
|
.extern_(S2, kind.clone(), Source::default())
|
|
.and_then(|o| o.resolve(S3, kind.clone(), src.clone()));
|
|
|
|
assert_eq!(Ok(Ident::Opaque(SPair(sym, S3), kind, src)), result);
|
|
}
|
|
|
|
// Identifier first, then extern
|
|
#[test]
|
|
fn redeclare_compatible_resolves_post() {
|
|
let sym = "extern_re_post".into();
|
|
let kind = IdentKind::Class(Dim::Vector);
|
|
let src = Source {
|
|
desc: Some("okay".into()),
|
|
..Default::default()
|
|
};
|
|
|
|
// Compatible kind, should resolve.
|
|
let result = Ident::declare(SPair(sym, S1))
|
|
.resolve(S2, kind.clone(), src.clone())
|
|
.and_then(|o| o.extern_(S3, kind.clone(), Source::default()));
|
|
|
|
// Note that we keep the span of the concrete identifier,
|
|
// despite the extern being encountered later.
|
|
assert_eq!(Ok(Ident::Opaque(SPair(sym, S2), kind, src)), result,);
|
|
}
|
|
|
|
#[test]
|
|
fn redeclare_another_extern() {
|
|
let sym = "extern_extern".into();
|
|
let kind = IdentKind::Class(Dim::Scalar);
|
|
let src_first = Source {
|
|
desc: Some("first src".into()),
|
|
..Default::default()
|
|
};
|
|
let src_second = Source {
|
|
desc: Some("second src".into()),
|
|
..Default::default()
|
|
};
|
|
|
|
let result = Ident::declare(SPair(sym, S1))
|
|
.extern_(S2, kind.clone(), src_first.clone())
|
|
.and_then(|o| o.extern_(S3, kind.clone(), src_second));
|
|
|
|
// Note that, if it resolves, it should keep what is
|
|
// _existing_, meaning that it must keep the first src.
|
|
assert_eq!(Ok(Ident::Extern(SPair(sym, S2), kind, src_first)), result);
|
|
}
|
|
|
|
// Extern first, then identifier
|
|
#[test]
|
|
fn redeclare_post_incompatible_kind() {
|
|
let sym = "extern_re_bad_post".into();
|
|
let kind = IdentKind::Class(Dim::Matrix);
|
|
let src = Source {
|
|
desc: Some("bad kind".into()),
|
|
..Default::default()
|
|
};
|
|
|
|
let orig = Ident::declare(SPair(sym, S1))
|
|
.extern_(S2, kind.clone(), Source::default())
|
|
.unwrap();
|
|
|
|
// Incompatible kind
|
|
let kind_bad = IdentKind::Meta;
|
|
assert_eq!(
|
|
orig.clone().resolve(S3, kind_bad.clone(), src),
|
|
Err((
|
|
orig,
|
|
TransitionError::ExternResolution(
|
|
SPair(sym, S2),
|
|
kind,
|
|
(kind_bad, S3)
|
|
)
|
|
)),
|
|
);
|
|
}
|
|
|
|
// Identifier first, then extern
|
|
#[test]
|
|
fn redeclare_pre_incompatible_kind() {
|
|
let sym = "extern_re_bad_pre".into();
|
|
let kind_orig = IdentKind::Class(Dim::Vector);
|
|
let src = Source {
|
|
desc: Some("bad kind".into()),
|
|
..Default::default()
|
|
};
|
|
|
|
let orig = Ident::declare(SPair(sym, S1))
|
|
.resolve(S2, kind_orig.clone(), src.clone())
|
|
.unwrap();
|
|
|
|
// Extern with incompatible kind.
|
|
let kind_extern = IdentKind::Meta;
|
|
|
|
assert_eq!(
|
|
orig.clone()
|
|
.extern_(S3, kind_extern.clone(), Source::default()),
|
|
Err((
|
|
orig,
|
|
TransitionError::ExternResolution(
|
|
SPair(sym, S2),
|
|
kind_orig,
|
|
(kind_extern, S3)
|
|
)
|
|
)),
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn add_fragment_to_ident() {
|
|
let sym = "tofrag".into();
|
|
let src = Source {
|
|
generated: true,
|
|
..Default::default()
|
|
};
|
|
|
|
let kind = IdentKind::Meta;
|
|
let ident = Ident::declare(SPair(sym, S1))
|
|
.resolve(S2, kind.clone(), src.clone())
|
|
.unwrap();
|
|
let text = FragmentText::from("a fragment");
|
|
|
|
assert_eq!(
|
|
ident.set_fragment(text.clone()),
|
|
Ok(Ident::IdentFragment(SPair(sym, S2), kind, src, text)),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn resolved_on_fragment() {
|
|
let sym = "tofrag resolved".into();
|
|
let src = Source {
|
|
generated: true,
|
|
..Default::default()
|
|
};
|
|
|
|
let kind = IdentKind::Meta;
|
|
let ident = Ident::declare(SPair(sym, S1))
|
|
.resolve(S2, kind.clone(), src.clone())
|
|
.unwrap();
|
|
let text = FragmentText::from("a fragment for resolved()");
|
|
|
|
assert_eq!(
|
|
ident.set_fragment(text.clone()).unwrap().resolved(),
|
|
Ok((
|
|
&Ident::IdentFragment(SPair(sym, S2), kind, src, text),
|
|
SPair(sym, S2),
|
|
)),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn add_fragment_to_fragment_fails() {
|
|
let sym = "badsym".into();
|
|
let ident = Ident::declare(SPair(sym, S1))
|
|
.resolve(S2, IdentKind::Meta, Source::default())
|
|
.unwrap();
|
|
|
|
let ident_with_frag = ident
|
|
.set_fragment("orig fragment".into())
|
|
.expect("set_fragment failed");
|
|
|
|
// Since it's already a fragment, this should fail.
|
|
assert_eq!(
|
|
ident_with_frag.clone().set_fragment("replacement".into()),
|
|
Err((
|
|
ident_with_frag,
|
|
TransitionError::BadFragmentDest(SPair(sym, S2))
|
|
)),
|
|
);
|
|
}
|
|
|
|
mod override_ {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn declare_virtual_ident_first() {
|
|
let sym = "virtual".into();
|
|
let over_src_name = "src".into();
|
|
let kind = IdentKind::Meta;
|
|
|
|
let virt = Ident::declare(SPair(sym, S1))
|
|
.resolve(
|
|
S2,
|
|
kind.clone(),
|
|
Source {
|
|
virtual_: true,
|
|
..Default::default()
|
|
},
|
|
)
|
|
.unwrap();
|
|
|
|
let over_src = Source {
|
|
virtual_: true, // this needn't be set, but see below
|
|
override_: true,
|
|
src: Some(over_src_name),
|
|
..Default::default()
|
|
};
|
|
|
|
let result = virt.resolve(S3, kind.clone(), over_src.clone());
|
|
|
|
// Overriding should clear any virtual flag that may have
|
|
// been set to prevent override-overrides.
|
|
let expected_src = Source {
|
|
virtual_: false,
|
|
..over_src
|
|
};
|
|
|
|
assert_eq!(
|
|
Ok(Ident::Opaque(SPair(sym, S3), kind, expected_src)),
|
|
result
|
|
);
|
|
}
|
|
|
|
// Override is encountered before the virtual
|
|
#[test]
|
|
fn declare_virtual_ident_after_override() {
|
|
let sym = "virtual_second".into();
|
|
let virt_src_name = "virt_src".into();
|
|
let kind = IdentKind::Meta;
|
|
|
|
let over_src = Source {
|
|
virtual_: true, // this needn't be set, but see below
|
|
override_: true,
|
|
..Default::default()
|
|
};
|
|
|
|
let over = Ident::declare(SPair(sym, S1))
|
|
.resolve(S2, kind.clone(), over_src.clone())
|
|
.unwrap();
|
|
|
|
let virt_src = Source {
|
|
virtual_: true,
|
|
src: Some(virt_src_name),
|
|
..Default::default()
|
|
};
|
|
|
|
let result = over.resolve(S3, kind.clone(), virt_src.clone());
|
|
|
|
// Overriding should clear any virtual flag that may have
|
|
// been set to prevent override-overrides. We should also
|
|
// take the override source even though virtual was second.
|
|
let expected_src = Source {
|
|
virtual_: false,
|
|
..over_src
|
|
};
|
|
|
|
assert_eq!(
|
|
Ok(Ident::Opaque(SPair(sym, S3), kind, expected_src)),
|
|
result
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn declare_override_non_virtual() {
|
|
let sym = "non_virtual".into();
|
|
let kind = IdentKind::Meta;
|
|
|
|
let non_virt = Ident::declare(SPair(sym, S1))
|
|
.resolve(
|
|
S2,
|
|
kind.clone(),
|
|
Source {
|
|
virtual_: false,
|
|
..Default::default()
|
|
},
|
|
)
|
|
.unwrap();
|
|
|
|
let over_src = Source {
|
|
override_: true,
|
|
..Default::default()
|
|
};
|
|
|
|
// This isn't the purpose of the test, but we want to make
|
|
// sure that the non-virtual override error occurs before
|
|
// the kind error.
|
|
let bad_kind = IdentKind::Cgen(Dim::Vector);
|
|
|
|
assert_eq!(
|
|
non_virt.clone().resolve(S3, bad_kind, over_src.clone()),
|
|
Err((
|
|
non_virt,
|
|
TransitionError::NonVirtualOverride(SPair(sym, S2), S3)
|
|
))
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn declare_virtual_ident_incompatible_kind() {
|
|
let sym = "virtual".into();
|
|
let src_sym: SymbolId = "src".into();
|
|
let kind = IdentKind::Meta;
|
|
|
|
let virt = Ident::declare(SPair(sym, S1))
|
|
.resolve(
|
|
S2,
|
|
kind.clone(),
|
|
Source {
|
|
virtual_: true,
|
|
..Default::default()
|
|
},
|
|
)
|
|
.unwrap();
|
|
|
|
let over_src = Source {
|
|
override_: true,
|
|
src: Some(src_sym),
|
|
..Default::default()
|
|
};
|
|
|
|
let bad_kind = IdentKind::Cgen(Dim::Vector);
|
|
|
|
assert_eq!(
|
|
virt.clone().resolve(S3, bad_kind.clone(), over_src.clone()),
|
|
Err((
|
|
virt,
|
|
TransitionError::VirtualOverrideKind(
|
|
SPair(sym, S2),
|
|
kind,
|
|
(bad_kind, S3)
|
|
)
|
|
)),
|
|
);
|
|
}
|
|
|
|
// Encounter virtual first and override second should cause the
|
|
// fragment to be cleared to make way for the new fragment.
|
|
#[test]
|
|
fn declare_override_virtual_ident_fragment_virtual_first() {
|
|
let sym = "virtual".into();
|
|
let over_src = "src".into();
|
|
let kind = IdentKind::Meta;
|
|
|
|
// Remember: override is going to come first...
|
|
let over_src = Source {
|
|
override_: true,
|
|
src: Some(over_src),
|
|
..Default::default()
|
|
};
|
|
|
|
// ...and virt second.
|
|
let virt_src = Source {
|
|
virtual_: true,
|
|
..Default::default()
|
|
};
|
|
|
|
let over = Ident::declare(SPair(sym, S1))
|
|
.resolve(S2, kind.clone(), over_src.clone())
|
|
.unwrap();
|
|
|
|
// So we should _keep_ this fragment, since it represent the
|
|
// override, even though it's appearing first.
|
|
let text = FragmentText::from("keep me");
|
|
let over_frag = over.set_fragment(text.clone());
|
|
|
|
assert_eq!(
|
|
over_frag,
|
|
Ok(Ident::IdentFragment(
|
|
SPair(sym, S2),
|
|
kind.clone(),
|
|
over_src.clone(),
|
|
text.clone(),
|
|
)),
|
|
);
|
|
|
|
// Overriding should _not_ have cleared the fragment since
|
|
// the override was encountered _first_, so we want to keep
|
|
// its fragment.
|
|
let result =
|
|
over_frag
|
|
.unwrap()
|
|
.resolve(S3, kind.clone(), virt_src.clone());
|
|
assert_eq!(
|
|
result,
|
|
Ok(Ident::IdentFragment(
|
|
SPair(sym, S3),
|
|
kind.clone(),
|
|
over_src.clone(),
|
|
text.clone()
|
|
)),
|
|
);
|
|
|
|
// Finally, after performing this transition, we will
|
|
// inevitably encounter the fragment for the virtual
|
|
// identifier, which we must ignore. So we must make sure
|
|
// that encountering it will not cause an error, because we
|
|
// still have an IdentFragment at this point.
|
|
assert_eq!(
|
|
Ok(Ident::IdentFragment(
|
|
SPair(sym, S3),
|
|
kind,
|
|
over_src.clone(),
|
|
text.clone()
|
|
)),
|
|
result.unwrap().set_fragment("virt fragment".into()),
|
|
);
|
|
}
|
|
|
|
// Encountering _override_ first and virtual second should _not_
|
|
// clear the fragment, otherwise the virtual fragment will take
|
|
// precedence over the override.
|
|
#[test]
|
|
fn declare_override_virtual_ident_fragment_override_first() {
|
|
let sym = "virtual".into();
|
|
let over_src = "src".into();
|
|
let kind = IdentKind::Meta;
|
|
|
|
let virt_src = Source {
|
|
virtual_: true,
|
|
..Default::default()
|
|
};
|
|
|
|
let virt = Ident::declare(SPair(sym, S1))
|
|
.resolve(S2, kind.clone(), virt_src.clone())
|
|
.unwrap();
|
|
let text = FragmentText::from("remove me");
|
|
let virt_frag = virt.set_fragment(text.clone());
|
|
|
|
assert_eq!(
|
|
virt_frag,
|
|
Ok(Ident::IdentFragment(
|
|
SPair(sym, S2),
|
|
kind.clone(),
|
|
virt_src,
|
|
text
|
|
)),
|
|
);
|
|
|
|
let over_src = Source {
|
|
override_: true,
|
|
src: Some(over_src),
|
|
..Default::default()
|
|
};
|
|
|
|
assert_eq!(
|
|
virt_frag
|
|
.unwrap()
|
|
.resolve(S3, kind.clone(), over_src.clone()),
|
|
// The act of overriding the object should have cleared any
|
|
// existing fragment, making way for a new fragment to take its
|
|
// place as soon as it is discovered. (So, back to an
|
|
// Ident::Ident.)
|
|
Ok(Ident::Opaque(SPair(sym, S3), kind, over_src)),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn declare_override_virtual_ident_fragment_incompatible_type() {
|
|
let sym = "virtual".into();
|
|
let over_src = "src".into();
|
|
let kind = IdentKind::Meta;
|
|
|
|
let virt_src = Source {
|
|
virtual_: true,
|
|
..Default::default()
|
|
};
|
|
|
|
let virt = Ident::declare(SPair(sym, S1))
|
|
.resolve(S2, kind.clone(), virt_src.clone())
|
|
.unwrap();
|
|
let virt_frag = virt.set_fragment("".into()).unwrap();
|
|
|
|
let over_src = Source {
|
|
override_: true,
|
|
src: Some(over_src),
|
|
..Default::default()
|
|
};
|
|
|
|
let bad_kind = IdentKind::Cgen(Dim::Vector);
|
|
assert_eq!(
|
|
virt_frag
|
|
.clone()
|
|
.resolve(S3, bad_kind.clone(), over_src.clone()),
|
|
Err((
|
|
virt_frag,
|
|
TransitionError::VirtualOverrideKind(
|
|
SPair(sym, S2),
|
|
kind,
|
|
(bad_kind, S3)
|
|
)
|
|
)),
|
|
);
|
|
}
|
|
}
|
|
|
|
fn add_ident_kind_ignores(given: IdentKind, expected: IdentKind) {
|
|
let sym = "tofrag".into();
|
|
let src = Source {
|
|
generated: true,
|
|
..Default::default()
|
|
};
|
|
|
|
let obj = Ident::declare(SPair(sym, S1))
|
|
.resolve(S2, given, src.clone())
|
|
.unwrap();
|
|
|
|
let fragment = "a fragment".intern();
|
|
|
|
assert_eq!(
|
|
obj.set_fragment(fragment),
|
|
Ok(Ident::IdentFragment(
|
|
SPair(sym, S2),
|
|
expected,
|
|
src,
|
|
fragment
|
|
)),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn add_fragment_to_ident_map_head() {
|
|
add_ident_kind_ignores(IdentKind::MapHead, IdentKind::MapHead)
|
|
}
|
|
|
|
#[test]
|
|
fn add_fragment_to_ident_map_tail() {
|
|
add_ident_kind_ignores(IdentKind::MapTail, IdentKind::MapTail)
|
|
}
|
|
|
|
#[test]
|
|
fn add_fragment_to_ident_retmap_head() {
|
|
add_ident_kind_ignores(IdentKind::RetMapHead, IdentKind::RetMapHead)
|
|
}
|
|
|
|
#[test]
|
|
fn add_fragment_to_ident_retmap_tail() {
|
|
add_ident_kind_ignores(IdentKind::RetMapTail, IdentKind::RetMapTail)
|
|
}
|