blob: 968ec642c7367a649994939dcfafb574485fa77b [file] [log] [blame]
using J2N.Runtime.CompilerServices;
using Lucene.Net.Analysis.Fr;
using Lucene.Net.Analysis.In;
using Lucene.Net.Analysis.Miscellaneous;
using Lucene.Net.Analysis.Nl;
using Lucene.Net.Analysis.Path;
using Lucene.Net.Analysis.Sinks;
using Lucene.Net.Analysis.Snowball;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Analysis.Util;
using Lucene.Net.TestFramework.Analysis;
using Lucene.Net.Util;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using JCG = J2N.Collections.Generic;
namespace Lucene.Net.Analysis.Core
{
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// <summary>
/// Tests that any newly added Tokenizers/TokenFilters/CharFilters have a
/// corresponding factory (and that the SPI configuration is correct)
/// </summary>
public class TestAllAnalyzersHaveFactories : LuceneTestCase
{
// these are test-only components (e.g. test-framework)
private static readonly ISet<Type> testComponents = new JCG.HashSet<Type>(IdentityEqualityComparer<Type>.Default);
static TestAllAnalyzersHaveFactories()
{
testComponents.addAll(new Type[] {
typeof(MockTokenizer),
typeof(MockCharFilter),
typeof(MockFixedLengthPayloadFilter),
typeof(MockGraphTokenFilter),
typeof(MockHoleInjectingTokenFilter),
typeof(MockRandomLookaheadTokenFilter),
typeof(MockTokenFilter),
typeof(MockVariableLengthPayloadFilter),
typeof(ValidatingTokenFilter),
typeof(CrankyTokenFilter)
});
crazyComponents.addAll(new Type[] {
typeof(CachingTokenFilter),
typeof(TeeSinkTokenFilter),
// LUCENENET: Added this specialized BufferedCharFilter which doesn't need a factory
typeof(BufferedCharFilter)
});
#pragma warning disable 612, 618
deprecatedDuplicatedComponents.addAll(new Type[] {
typeof(DutchStemFilter),
typeof(FrenchStemFilter),
typeof(IndicTokenizer)
});
#pragma warning restore 612, 618
oddlyNamedComponents.addAll(new Type[] {
typeof(ReversePathHierarchyTokenizer), // this is supported via an option to PathHierarchyTokenizer's factory
typeof(SnowballFilter), // this is called SnowballPorterFilterFactory
typeof(PatternKeywordMarkerFilter),
typeof(SetKeywordMarkerFilter)
});
}
// these are 'crazy' components like cachingtokenfilter. does it make sense to add factories for these?
private static readonly ISet<Type> crazyComponents = new JCG.HashSet<Type>(IdentityEqualityComparer<Type>.Default);
// these are deprecated components that are just exact dups of other functionality: they dont need factories
// (they never had them)
private static readonly ISet<Type> deprecatedDuplicatedComponents = new JCG.HashSet<Type>(IdentityEqualityComparer<Type>.Default);
// these are oddly-named (either the actual analyzer, or its factory)
// they do actually have factories.
// TODO: clean this up!
private static readonly ISet<Type> oddlyNamedComponents = new JCG.HashSet<Type>(IdentityEqualityComparer<Type>.Default);
private static readonly IResourceLoader loader = new StringMockResourceLoader("");
[Test]
public virtual void Test()
{
IList<Type> analysisClasses = typeof(StandardAnalyzer).GetTypeInfo().Assembly.GetTypes()
.Where(c =>
{
var typeInfo = c.GetTypeInfo();
return !typeInfo.IsAbstract && typeInfo.IsPublic && !typeInfo.IsInterface && typeInfo.IsClass && (typeInfo.GetCustomAttribute<ObsoleteAttribute>() == null)
&& !testComponents.Contains(c) && !crazyComponents.Contains(c) && !oddlyNamedComponents.Contains(c) && !deprecatedDuplicatedComponents.Contains(c)
&& (typeInfo.IsSubclassOf(typeof(Tokenizer)) || typeInfo.IsSubclassOf(typeof(TokenFilter)) || typeInfo.IsSubclassOf(typeof(CharFilter)));
})
.ToList();
foreach (Type c in analysisClasses)
{
IDictionary<string, string> args = new Dictionary<string, string>();
args["luceneMatchVersion"] = TEST_VERSION_CURRENT.ToString();
if (c.GetTypeInfo().IsSubclassOf(typeof(Tokenizer)))
{
string clazzName = c.Name;
assertTrue(clazzName.EndsWith("Tokenizer", StringComparison.Ordinal));
string simpleName = clazzName.Substring(0, clazzName.Length - 9);
assertNotNull(TokenizerFactory.LookupClass(simpleName));
TokenizerFactory instance = null;
try
{
instance = TokenizerFactory.ForName(simpleName, args);
assertNotNull(instance);
if (instance is IResourceLoaderAware)
{
((IResourceLoaderAware)instance).Inform(loader);
}
assertSame(c, instance.Create(new StringReader("")).GetType());
}
catch (System.ArgumentException e)
{
if (e.InnerException is MissingMethodException)
{
// there is no corresponding ctor available
throw; // LUCENENET: CA2200: Rethrow to preserve stack details (https://docs.microsoft.com/en-us/visualstudio/code-quality/ca2200-rethrow-to-preserve-stack-details)
}
// TODO: For now pass because some factories have not yet a default config that always works
}
}
else if (c.GetTypeInfo().IsSubclassOf(typeof(TokenFilter)))
{
string clazzName = c.Name;
assertTrue(clazzName.EndsWith("Filter", StringComparison.Ordinal));
string simpleName = clazzName.Substring(0, clazzName.Length - (clazzName.EndsWith("TokenFilter", StringComparison.Ordinal) ? 11 : 6));
assertNotNull(TokenFilterFactory.LookupClass(simpleName));
TokenFilterFactory instance = null;
try
{
instance = TokenFilterFactory.ForName(simpleName, args);
assertNotNull(instance);
if (instance is IResourceLoaderAware)
{
((IResourceLoaderAware)instance).Inform(loader);
}
Type createdClazz = instance.Create(new KeywordTokenizer(new StringReader(""))).GetType();
// only check instance if factory have wrapped at all!
if (typeof(KeywordTokenizer) != createdClazz)
{
assertSame(c, createdClazz);
}
}
catch (System.ArgumentException e)
{
if (e.InnerException is MissingMethodException)
{
// there is no corresponding ctor available
throw; // LUCENENET: CA2200: Rethrow to preserve stack details (https://docs.microsoft.com/en-us/visualstudio/code-quality/ca2200-rethrow-to-preserve-stack-details)
}
// TODO: For now pass because some factories have not yet a default config that always works
}
}
else if (c.GetTypeInfo().IsSubclassOf(typeof(CharFilter)))
{
string clazzName = c.Name;
assertTrue(clazzName.EndsWith("CharFilter", StringComparison.Ordinal));
string simpleName = clazzName.Substring(0, clazzName.Length - 10);
assertNotNull(CharFilterFactory.LookupClass(simpleName));
CharFilterFactory instance = null;
try
{
instance = CharFilterFactory.ForName(simpleName, args);
assertNotNull(instance);
if (instance is IResourceLoaderAware)
{
((IResourceLoaderAware)instance).Inform(loader);
}
Type createdClazz = instance.Create(new StringReader("")).GetType();
// only check instance if factory have wrapped at all!
if (typeof(StringReader) != createdClazz)
{
assertSame(c, createdClazz);
}
}
catch (System.ArgumentException e)
{
if (e.InnerException is MissingMethodException)
{
// there is no corresponding ctor available
throw; // LUCENENET: CA2200: Rethrow to preserve stack details (https://docs.microsoft.com/en-us/visualstudio/code-quality/ca2200-rethrow-to-preserve-stack-details)
}
// TODO: For now pass because some factories have not yet a default config that always works
}
}
}
}
}
}