using NATS.Server.Subscriptions;

namespace NATS.Server.Core.Tests;

public class SubjectMatchTests
{
    [Theory]
    [InlineData("foo", true)]
    [InlineData("foo.bar", true)]
    [InlineData("foo.bar.baz", true)]
    [InlineData("foo.*", true)]
    [InlineData("foo.>", true)]
    [InlineData(">", true)]
    [InlineData("*", true)]
    [InlineData("*.bar", true)]
    [InlineData("foo.*.baz", true)]
    [InlineData("", false)]
    [InlineData("foo.", false)]
    [InlineData(".foo", false)]
    [InlineData("foo..bar", false)]
    [InlineData("foo.>.bar", false)]  // > must be last token
    [InlineData("foo bar", false)]    // no spaces
    [InlineData("foo\tbar", false)]   // no tabs
    public void IsValidSubject(string subject, bool expected)
    {
        SubjectMatch.IsValidSubject(subject).ShouldBe(expected);
    }

    [Theory]
    [InlineData("foo", true)]
    [InlineData("foo.bar.baz", true)]
    [InlineData("foo.*", false)]
    [InlineData("foo.>", false)]
    [InlineData(">", false)]
    [InlineData("*", false)]
    public void IsValidPublishSubject(string subject, bool expected)
    {
        SubjectMatch.IsValidPublishSubject(subject).ShouldBe(expected);
    }

    [Theory]
    [InlineData("foo", "foo", true)]
    [InlineData("foo", "bar", false)]
    [InlineData("foo.bar", "foo.*", true)]
    [InlineData("foo.bar", "*.bar", true)]
    [InlineData("foo.bar", "*.*", true)]
    [InlineData("foo.bar.baz", "foo.>", true)]
    [InlineData("foo.bar.baz", ">", true)]
    [InlineData("foo.bar", "foo.>", true)]
    [InlineData("foo", "foo.>", false)]
    [InlineData("foo.bar.baz", "foo.*", false)]
    [InlineData("foo.bar", "foo.bar.>", false)]
    public void MatchLiteral(string literal, string pattern, bool expected)
    {
        SubjectMatch.MatchLiteral(literal, pattern).ShouldBe(expected);
    }

    [Theory]
    [InlineData("foo.bar.baz", 3)]
    [InlineData("foo", 1)]
    [InlineData("a.b.c.d.e", 5)]
    [InlineData("", 0)]
    public void NumTokens(string subject, int expected)
    {
        SubjectMatch.NumTokens(subject).ShouldBe(expected);
    }

    [Theory]
    [InlineData("foo.bar.baz", 0, "foo")]
    [InlineData("foo.bar.baz", 1, "bar")]
    [InlineData("foo.bar.baz", 2, "baz")]
    [InlineData("foo", 0, "foo")]
    [InlineData("foo.bar.baz", 5, "")]
    public void TokenAt(string subject, int index, string expected)
    {
        SubjectMatch.TokenAt(subject, index).ToString().ShouldBe(expected);
    }

    [Theory]
    [InlineData("foo.bar", "foo.bar", true)]
    [InlineData("foo.bar", "foo.baz", false)]
    [InlineData("foo.*", "foo.bar", true)]
    [InlineData("foo.*", "foo.>", true)]
    [InlineData("foo.>", "foo.bar.baz", true)]
    [InlineData(">", "foo.bar", true)]
    [InlineData("foo.*", "bar.*", false)]
    [InlineData("foo.*.baz", "foo.bar.*", true)]
    [InlineData("*.bar", "foo.*", true)]
    [InlineData("foo.*", "bar.>", false)]
    public void SubjectsCollide(string subj1, string subj2, bool expected)
    {
        SubjectMatch.SubjectsCollide(subj1, subj2).ShouldBe(expected);
    }

    [Theory]
    [InlineData("foo\0bar", true, false)]
    [InlineData("foo\0bar", false, true)]
    [InlineData("foo.bar", true, true)]
    public void IsValidSubject_checkRunes(string subject, bool checkRunes, bool expected)
    {
        SubjectMatch.IsValidSubject(subject, checkRunes).ShouldBe(expected);
    }
}
