blob: 2e3ae58c20cf6e181568cda75e6e7e54e6717151 [file] [log] [blame]
using Lucene.Net.Codecs;
using Lucene.Net.Configuration;
using NUnit.Framework;
using System;
using System.Threading;
namespace Lucene.Net.Util
{
/*
* 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>
/// <see cref="LuceneTestFrameworkInitializer"/> may be subclassed by end users in order to
/// use standard dependency injection techniques for classes under test. A subclass of <see cref="LuceneTestFrameworkInitializer"/>
/// will be executed automatically by NUnit. To work properly with the Lucene.NET test framework, the subclass
/// must be placed outside of all namespaces, which ensures it is only executed 1 time per test assembly.
/// <para/>
/// The following abstract factories can be overridden for testing purposes:
/// <list type="table">
/// <listheader>
/// <term>Abstraction</term>
/// <term>Factory Method Name</term>
/// <term>Default</term>
/// </listheader>
/// <item>
/// <term><see cref="ICodecFactory"/></term>
/// <term><see cref="CodecFactory"/></term>
/// <term><see cref="TestCodecFactory"/></term>
/// </item>
/// <item>
/// <term><see cref="IDocValuesFormatFactory"/></term>
/// <term><see cref="DocValuesFormatFactory"/></term>
/// <term><see cref="TestDocValuesFormatFactory"/></term>
/// </item>
/// <item>
/// <term><see cref="IPostingsFormatFactory"/></term>
/// <term><see cref="PostingsFormatFactory"/></term>
/// <term><see cref="TestPostingsFormatFactory"/></term>
/// </item>
/// <item>
/// <term><see cref="IConfigurationFactory"/></term>
/// <term><see cref="ConfigurationFactory"/></term>
/// <term><see cref="TestConfigurationFactory"/></term>
/// </item>
/// </list>
/// <para/>
/// <b>Example:</b>
/// <code>
/// // IMPORTANT: Do not put the initializer in a namespace
/// public class MyTestFrameworkInitializer : LuceneTestFrameworkInitializer
/// {
/// protected override IConfigurationFactory LoadConfigurationFactory()
/// {
/// // Inject a custom configuration factory
/// return new MyConfigurationFactory();
/// }
///
/// protected override void TestFrameworkSetUp()
/// {
/// // Inject a custom configuration factory
/// ConfigurationFactory = new MyConfigurationFactory();
///
/// // Do any additional dependency injection setup here
/// }
/// }
/// </code>
/// </summary>
[SetUpFixture]
public abstract class LuceneTestFrameworkInitializer
{
// Initialization target must be static to ensure the initializer only fires one
// time per application run (even when the static EnsureInitialized() method is called).
private static object initializationTarget;
// LUCENENET specific factory methods to scan the test framework for codecs/docvaluesformats/postingsformats only once
/// <summary>
/// The <see cref="ICodecFactory"/> implementation to use to load codecs during testing.
/// </summary>
protected static ICodecFactory CodecFactory { get; set; } = new TestCodecFactory();
/// <summary>
/// The <see cref="IDocValuesFormatFactory"/> implementation to use to load doc values during testing.
/// </summary>
protected static IDocValuesFormatFactory DocValuesFormatFactory { get; set; } = new TestDocValuesFormatFactory();
/// <summary>
/// The <see cref="IPostingsFormatFactory"/> implementation to use to load postings formats during testing.
/// </summary>
protected static IPostingsFormatFactory PostingsFormatFactory { get; set; } = new TestPostingsFormatFactory();
/// <summary>
/// The <see cref="IConfigurationFactory"/> implementation to use to load configuration settings during testing.
/// See: <a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/">
/// https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/</a>.
/// </summary>
[CLSCompliant(false)]
protected static IConfigurationFactory ConfigurationFactory { get; set; } = new TestConfigurationFactory();
/// <summary>
/// Overridden in a derived class, can be used to initialize factory instances that are
/// injected into Lucene.NET during test operations, or perform other one-time initialization
/// of the test framework setup.
/// <para/>
/// NOTE: To initialize 1 time for your entire test library, only create a single derived class
/// and place it outside of any namespace.
/// </summary>
protected virtual void TestFrameworkSetUp()
{
// Runs only once per test framework run before all tests
}
/// <summary>
/// Overridden in a derived class, can be used to tear down classes one-time
/// for the test framework.
/// </summary>
protected virtual void TestFrameworkTearDown()
{
// Runs only once per test framework run after all tests
}
/// <summary>
/// When this class is derived in a test assembly, this method is automatically called
/// by NUnit one time before all tests run.
/// </summary>
[OneTimeSetUp]
protected void OneTimeSetUpBeforeTests()
{
try
{
TestFrameworkSetUp();
// Initialize of the test factories here, so that doesn't happen
// when EnsureInitialized() is called.
Initialize();
}
catch (Exception ex)
{
// Write the stack trace so we have something to go on if an error occurs here.
throw new Exception($"An exception occurred during OneTimeSetUpBeforeTests:\n{ex.ToString()}", ex);
}
}
/// <summary>
/// When this class is derived in a test assembly, this method is automatically called
/// by NUnit one time after all tests run.
/// </summary>
[OneTimeTearDown]
protected void OneTimeTearDownAfterTests()
{
try
{
TestFrameworkTearDown();
}
catch (Exception ex)
{
// Write the stack trace so we have something to go on if an error occurs here.
throw new Exception($"An exception occurred during OneTimeTearDownAfterTests:\n{ex.ToString()}", ex);
}
}
/// <summary>
/// The default implementation of the initializer that is simply used to initialize with the
/// default test factory implementations.
/// </summary>
private class DefaultLuceneTestFrameworkInitializer : LuceneTestFrameworkInitializer { }
/// <summary>
/// Can be called by an external source to ensure that the test framework has been initialized.
/// <see cref="Initialize()"/> only occurs if it hasn't already been called by NUnit in a subclass
/// of this class.
/// </summary>
internal static void EnsureInitialized()
{
new DefaultLuceneTestFrameworkInitializer().Initialize();
}
private void Initialize()
{
LazyInitializer.EnsureInitialized(ref initializationTarget, () =>
{
// Setup the factories
ConfigurationSettings.SetConfigurationFactory(ConfigurationFactory);
Codec.SetCodecFactory(CodecFactory);
DocValuesFormat.SetDocValuesFormatFactory(DocValuesFormatFactory);
PostingsFormat.SetPostingsFormatFactory(PostingsFormatFactory);
IncrementInitalizationCount(); // For testing
return new object(); // Placeholder to indicate our initializer has been run already
});
}
internal virtual void IncrementInitalizationCount()
{
}
}
}