// Copyright (c) Umbraco. // See LICENSE for more details. using System.Collections; using System.Data; using System.Data.Common; using System.Linq.Expressions; using Microsoft.Extensions.Options; using Moq; using NPoco; using NPoco.DatabaseTypes; using NPoco.Linq; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Infrastructure.Migrations.Install; using Umbraco.Cms.Infrastructure.Persistence; using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax; using Umbraco.Cms.Persistence.SqlServer.Services; namespace Umbraco.Cms.Tests.Common.TestHelpers; /// /// An implementation of for tests. /// /// /// Supports writing to the database, and logs Sql statements. /// Cannot support reading from the database, and throws. /// Tries to pretend it supports transactions, connections, etc. as best as possible. /// public class TestDatabase : IUmbracoDatabase { /// /// Initializes a new instance of the class. /// /// /// When both parameters are supplied, they should of course be consistent. /// public TestDatabase(DatabaseType databaseType = null, ISqlSyntaxProvider syntaxProvider = null) { DatabaseType = databaseType ?? new SqlServerDatabaseType(); SqlContext = new SqlContext(syntaxProvider ?? new SqlServerSyntaxProvider(Options.Create(new GlobalSettings())), DatabaseType, Mock.Of()); } /// /// Gets the database operations. /// public List Operations { get; } = new(); public void Dispose() { } public IDatabase OpenSharedConnection() => this; public void CloseSharedConnection() { } (List, List, List, List) IDatabaseQuery.FetchMultiple(Sql sql) => throw new NotImplementedException(); public int OneTimeCommandTimeout { get; set; } public MapperCollection Mappers { get; set; } public IPocoDataFactory PocoDataFactory { get; set; } public DatabaseType DatabaseType { get; } public List Interceptors { get; } public string ConnectionString { get; } public DbConnection Connection { get; } public DbTransaction Transaction { get; } public IDictionary Data { get; } public int CommandTimeout { get; set; } public ISqlContext SqlContext { get; } public string InstanceId { get; } public bool InTransaction { get; } public bool EnableSqlCount { get; set; } public int SqlCount { get; } IMapperCollection IDatabaseConfig.Mappers { get => Mappers; set => throw new NotImplementedException(); } IDatabaseType IDatabaseConfig.DatabaseType => DatabaseType; public int BulkInsertRecords(IEnumerable records) => throw new NotImplementedException(); public bool IsUmbracoInstalled() => true; public DatabaseSchemaResult ValidateSchema() => throw new NotImplementedException(); public DbParameter CreateParameter() => throw new NotImplementedException(); public void AddParameter(DbCommand cmd, object value) => throw new NotImplementedException(); public DbCommand CreateCommand(DbConnection connection, CommandType commandType, string sql, params object[] args) => throw new NotImplementedException(); public ITransaction GetTransaction() => throw new NotImplementedException(); public ITransaction GetTransaction(IsolationLevel isolationLevel) => throw new NotImplementedException(); public void SetTransaction(DbTransaction tran) => throw new NotImplementedException(); public void BeginTransaction() => Operations.Add(new Operation("BEGIN")); public void BeginTransaction(IsolationLevel isolationLevel) => Operations.Add(new Operation("BEGIN " + isolationLevel)); public void AbortTransaction() => Operations.Add(new Operation("ABORT")); public void CompleteTransaction() => Operations.Add(new Operation("COMMIT")); public int Execute(string sql, params object[] args) { Operations.Add(new Operation("EXECUTE", sql, args)); return default; } public int Execute(Sql sql) { Operations.Add(new Operation("EXECUTE", sql.SQL, sql.Arguments)); return default; } public int Execute(string sql, CommandType commandType, params object[] args) { Operations.Add(new Operation("EXECUTE", sql, args)); return default; } public T ExecuteScalar(string sql, params object[] args) { Operations.Add(new Operation("EXECUTE SCALAR", sql, args)); return default; } public T ExecuteScalar(Sql sql) { Operations.Add(new Operation("EXECUTE SCALAR", sql.SQL, sql.Arguments)); return default; } public T ExecuteScalar(string sql, CommandType commandType, params object[] args) { Operations.Add(new Operation("EXECUTE SCALAR", sql, args)); return default; } public Task ExecuteScalarAsync(string sql, CancellationToken token) => throw new NotImplementedException(); public Task ExecuteScalarAsync(string sql, object[] args, CancellationToken token) => throw new NotImplementedException(); public Task ExecuteScalarAsync(Sql sql, CancellationToken token) => throw new NotImplementedException(); public Task ExecuteAsync(string sql, CancellationToken token) => throw new NotImplementedException(); public Task ExecuteAsync(string sql, object[] args, CancellationToken token) => throw new NotImplementedException(); public Task ExecuteAsync(Sql sql, CancellationToken token) => throw new NotImplementedException(); public Task InsertAsync(string tableName, string primaryKeyName, object poco, CancellationToken token) => throw new NotImplementedException(); public object Insert(string tableName, string primaryKeyName, bool autoIncrement, T poco) => throw new NotImplementedException(); public object Insert(string tableName, string primaryKeyName, T poco) => throw new NotImplementedException(); public object Insert(T poco) => throw new NotImplementedException(); public void InsertBulk(IEnumerable pocos, InsertBulkOptions? options) => throw new NotImplementedException(); public Task InsertAsync(T poco, CancellationToken token) => throw new NotImplementedException(); public Task InsertBulkAsync(IEnumerable pocos, InsertBulkOptions? options, CancellationToken token) => throw new NotImplementedException(); public Task InsertBatchAsync(IEnumerable pocos, BatchOptions? options, CancellationToken token) => throw new NotImplementedException(); public Task UpdateAsync(object poco, CancellationToken token) => throw new NotImplementedException(); public Task UpdateAsync(object poco, IEnumerable columns, CancellationToken token) => throw new NotImplementedException(); public Task UpdateAsync(T poco, Expression> fields, CancellationToken token) => throw new NotImplementedException(); public Task UpdateBatchAsync(IEnumerable> pocos, BatchOptions? options, CancellationToken token) => throw new NotImplementedException(); public Task DeleteAsync(object poco, CancellationToken token) => throw new NotImplementedException(); public IAsyncUpdateQueryProvider UpdateManyAsync() => throw new NotImplementedException(); public IAsyncDeleteQueryProvider DeleteManyAsync() => throw new NotImplementedException(); public Task IsNewAsync(T poco, CancellationToken token) => throw new NotImplementedException(); public Task SaveAsync(T poco, CancellationToken token) => throw new NotImplementedException(); int IDatabase.InsertBatch(IEnumerable pocos, BatchOptions options) => throw new NotImplementedException(); public int Update(string tableName, string primaryKeyName, object poco, object primaryKeyValue) => throw new NotImplementedException(); public int Update(string tableName, string primaryKeyName, object poco) => throw new NotImplementedException(); public int Update(string tableName, string primaryKeyName, object poco, object primaryKeyValue, IEnumerable columns) => throw new NotImplementedException(); public int Update(string tableName, string primaryKeyName, object poco, IEnumerable columns) => throw new NotImplementedException(); public int Update(object poco, IEnumerable columns) => throw new NotImplementedException(); public int Update(object poco, object primaryKeyValue, IEnumerable columns) => throw new NotImplementedException(); public int Update(object poco) => throw new NotImplementedException(); public int Update(T poco, Expression> fields) => throw new NotImplementedException(); public int Update(object poco, object primaryKeyValue) => throw new NotImplementedException(); public int Update(string sql, params object[] args) => throw new NotImplementedException(); public int Update(Sql sql) => throw new NotImplementedException(); public int UpdateBatch(IEnumerable> pocos, BatchOptions options = null) => throw new NotImplementedException(); public IUpdateQueryProvider UpdateMany() => throw new NotImplementedException(); public int Delete(string tableName, string primaryKeyName, object poco) => throw new NotImplementedException(); public int Delete(string tableName, string primaryKeyName, object poco, object primaryKeyValue) => throw new NotImplementedException(); public int Delete(object poco) => throw new NotImplementedException(); public int Delete(string sql, params object[] args) => throw new NotImplementedException(); public int Delete(Sql sql) => throw new NotImplementedException(); public int Delete(object pocoOrPrimaryKey) => throw new NotImplementedException(); public IDeleteQueryProvider DeleteMany() => throw new NotImplementedException(); public void Save(T poco) => throw new NotImplementedException(); public bool IsNew(T poco) => throw new NotImplementedException(); public List Fetch(Type type, string sql, params object[] args) => throw new NotImplementedException(); public List Fetch(Type type, Sql sql) => throw new NotImplementedException(); public IEnumerable Query(Type type, string sql, params object[] args) => throw new NotImplementedException(); public IEnumerable Query(Type type, Sql sql) => throw new NotImplementedException(); public List Fetch() => throw new NotImplementedException(); public List Fetch(string sql, params object[] args) => throw new NotImplementedException(); public List Fetch(Sql sql) => throw new NotImplementedException(); public List Fetch(long page, long itemsPerPage, string sql, params object[] args) => throw new NotImplementedException(); public List Fetch(long page, long itemsPerPage, Sql sql) => throw new NotImplementedException(); public Page Page(long page, long itemsPerPage, string sql, params object[] args) => throw new NotImplementedException(); public Page Page(long page, long itemsPerPage, Sql sql) => throw new NotImplementedException(); public List SkipTake(long skip, long take, string sql, params object[] args) => throw new NotImplementedException(); public List SkipTake(long skip, long take, Sql sql) => throw new NotImplementedException(); public List FetchOneToMany(Expression> many, string sql, params object[] args) => throw new NotImplementedException(); public List FetchOneToMany(Expression> many, Sql sql) => throw new NotImplementedException(); public List FetchOneToMany(Expression> many, Func idFunc, string sql, params object[] args) => throw new NotImplementedException(); public List FetchOneToMany(Expression> many, Func idFunc, Sql sql) => throw new NotImplementedException(); public IEnumerable Query(string sql, params object[] args) => throw new NotImplementedException(); public IEnumerable Query(Sql sql) => throw new NotImplementedException(); public IQueryProviderWithIncludes Query() => throw new NotImplementedException(); public T SingleById(object primaryKey) => throw new NotImplementedException(); public T Single(string sql, params object[] args) => throw new NotImplementedException(); public T SingleInto(T instance, string sql, params object[] args) => throw new NotImplementedException(); public T SingleOrDefaultById(object primaryKey) => throw new NotImplementedException(); public T SingleOrDefault(string sql, params object[] args) => throw new NotImplementedException(); public T SingleOrDefaultInto(T instance, string sql, params object[] args) => throw new NotImplementedException(); public T First(string sql, params object[] args) => throw new NotImplementedException(); public T FirstInto(T instance, string sql, params object[] args) => throw new NotImplementedException(); public T FirstOrDefault(string sql, params object[] args) => throw new NotImplementedException(); public T FirstOrDefaultInto(T instance, string sql, params object[] args) => throw new NotImplementedException(); public T Single(Sql sql) => throw new NotImplementedException(); public T SingleInto(T instance, Sql sql) => throw new NotImplementedException(); public T SingleOrDefault(Sql sql) => throw new NotImplementedException(); public T SingleOrDefaultInto(T instance, Sql sql) => throw new NotImplementedException(); public T First(Sql sql) => throw new NotImplementedException(); public T FirstInto(T instance, Sql sql) => throw new NotImplementedException(); public T FirstOrDefault(Sql sql) => throw new NotImplementedException(); public T FirstOrDefaultInto(T instance, Sql sql) => throw new NotImplementedException(); public Dictionary Dictionary(Sql sql) => throw new NotImplementedException(); public Dictionary Dictionary(string sql, params object[] args) => throw new NotImplementedException(); public bool Exists(object primaryKey) => throw new NotImplementedException(); public TRet FetchMultiple(Func, List, TRet> cb, string sql, params object[] args) => throw new NotImplementedException(); public TRet FetchMultiple(Func, List, List, TRet> cb, string sql, params object[] args) => throw new NotImplementedException(); public TRet FetchMultiple(Func, List, List, List, TRet> cb, string sql, params object[] args) => throw new NotImplementedException(); public TRet FetchMultiple(Func, List, TRet> cb, Sql sql) => throw new NotImplementedException(); public TRet FetchMultiple(Func, List, List, TRet> cb, Sql sql) => throw new NotImplementedException(); public TRet FetchMultiple(Func, List, List, List, TRet> cb, Sql sql) => throw new NotImplementedException(); (List, List) IDatabaseQuery.FetchMultiple(string sql, params object[] args) => throw new NotImplementedException(); (List, List, List) IDatabaseQuery.FetchMultiple(string sql, params object[] args) => throw new NotImplementedException(); (List, List, List, List) IDatabaseQuery.FetchMultiple(string sql, params object[] args) => throw new NotImplementedException(); (List, List) IDatabaseQuery.FetchMultiple(Sql sql) => throw new NotImplementedException(); (List, List, List) IDatabaseQuery.FetchMultiple(Sql sql) => throw new NotImplementedException(); public Task SingleAsync(string sql, CancellationToken token) => throw new NotImplementedException(); public Task SingleAsync(string sql, object[] args, CancellationToken token) => throw new NotImplementedException(); public Task SingleAsync(Sql sql, CancellationToken token) => throw new NotImplementedException(); public Task SingleOrDefaultAsync(string sql, CancellationToken token) => throw new NotImplementedException(); public Task SingleOrDefaultAsync(string sql, object[] args, CancellationToken token) => throw new NotImplementedException(); public Task SingleOrDefaultAsync(Sql sql, CancellationToken token) => throw new NotImplementedException(); public Task SingleByIdAsync(object primaryKey, CancellationToken token) => throw new NotImplementedException(); public Task SingleOrDefaultByIdAsync(object primaryKey, CancellationToken token) => throw new NotImplementedException(); public Task FirstAsync(string sql, CancellationToken token) => throw new NotImplementedException(); public Task FirstAsync(string sql, object[] args, CancellationToken token) => throw new NotImplementedException(); public Task FirstAsync(Sql sql, CancellationToken token) => throw new NotImplementedException(); public Task FirstOrDefaultAsync(string sql, CancellationToken token) => throw new NotImplementedException(); public Task FirstOrDefaultAsync(string sql, object[] args, CancellationToken token) => throw new NotImplementedException(); public Task FirstOrDefaultAsync(Sql sql, CancellationToken token) => throw new NotImplementedException(); public IAsyncQueryProviderWithIncludes QueryAsync() => throw new NotImplementedException(); IAsyncEnumerable IAsyncQueryDatabase.QueryAsync(string sql, CancellationToken token) => throw new NotImplementedException(); IAsyncEnumerable IAsyncQueryDatabase.QueryAsync(string sql, object[] args, CancellationToken token) => throw new NotImplementedException(); IAsyncEnumerable IAsyncQueryDatabase.QueryAsync(Sql sql, CancellationToken token) => throw new NotImplementedException(); public IAsyncQueryProviderWithIncludes QueryAsync(CancellationToken token) => throw new NotImplementedException(); public Task> FetchAsync(string sql, CancellationToken token) => throw new NotImplementedException(); public Task> FetchAsync(string sql, object[] args, CancellationToken token) => throw new NotImplementedException(); public Task> FetchAsync(Sql sql, CancellationToken token) => throw new NotImplementedException(); public Task> FetchAsync(CancellationToken token) => throw new NotImplementedException(); public Task> PageAsync(long page, long itemsPerPage, string sql, CancellationToken cancellationToken = default) => throw new NotImplementedException(); public Task> PageAsync(long page, long itemsPerPage, string sql, object[] args, CancellationToken token) => throw new NotImplementedException(); public Task> PageAsync(long page, long itemsPerPage, Sql sql, CancellationToken token) => throw new NotImplementedException(); public Task> FetchAsync(long page, long itemsPerPage, string sql, CancellationToken token) => throw new NotImplementedException(); public Task> FetchAsync(long page, long itemsPerPage, string sql, object[] args, CancellationToken token) => throw new NotImplementedException(); public Task> FetchAsync(long page, long itemsPerPage, Sql sql, CancellationToken token) => throw new NotImplementedException(); public Task> SkipTakeAsync(long skip, long take, string sql, CancellationToken token) => throw new NotImplementedException(); public Task> SkipTakeAsync(long skip, long take, string sql, object[] args, CancellationToken token) => throw new NotImplementedException(); public Task> SkipTakeAsync(long skip, long take, Sql sql, CancellationToken token) => throw new NotImplementedException(); public Task FetchMultipleAsync(Func, List, TRet> cb, string sql, object[] args, CancellationToken token) => throw new NotImplementedException(); public Task FetchMultipleAsync(Func, List, List, TRet> cb, string sql, object[] args, CancellationToken token) => throw new NotImplementedException(); public Task FetchMultipleAsync(Func, List, List, List, TRet> cb, string sql, object[] args, CancellationToken token) => throw new NotImplementedException(); public Task FetchMultipleAsync(Func, List, TRet> cb, Sql sql, CancellationToken token) => throw new NotImplementedException(); public Task FetchMultipleAsync(Func, List, List, TRet> cb, Sql sql, CancellationToken token) => throw new NotImplementedException(); public Task FetchMultipleAsync(Func, List, List, List, TRet> cb, Sql sql, CancellationToken token) => throw new NotImplementedException(); public Task<(List, List)> FetchMultipleAsync(string sql, object[] args, CancellationToken token) => throw new NotImplementedException(); public Task<(List, List, List)> FetchMultipleAsync(string sql, object[] args, CancellationToken token) => throw new NotImplementedException(); public Task<(List, List, List, List)> FetchMultipleAsync(string sql, object[] args, CancellationToken token) => throw new NotImplementedException(); public Task<(List, List)> FetchMultipleAsync(Sql sql, CancellationToken token) => throw new NotImplementedException(); public Task<(List, List, List)> FetchMultipleAsync(Sql sql, CancellationToken token) => throw new NotImplementedException(); public Task<(List, List, List, List)> FetchMultipleAsync(Sql sql, CancellationToken token) => throw new NotImplementedException(); public Task FetchMultipleAsync(Func, List, TRet> cb, string sql, CancellationToken cancellationToken = default) => throw new NotImplementedException(); public Task FetchMultipleAsync(Func, List, List, TRet> cb, string sql, CancellationToken cancellationToken = default) => throw new NotImplementedException(); public Task FetchMultipleAsync(Func, List, List, List, TRet> cb, string sql, CancellationToken cancellationToken = default) => throw new NotImplementedException(); public Task<(List, List)> FetchMultipleAsync(string sql, CancellationToken cancellationToken = default) => throw new NotImplementedException(); public Task<(List, List, List)> FetchMultipleAsync(string sql, CancellationToken cancellationToken = default) => throw new NotImplementedException(); public Task<(List, List, List, List)> FetchMultipleAsync(string sql, CancellationToken cancellationToken = default) => throw new NotImplementedException(); public void BuildPageQueries(long skip, long take, string sql, ref object[] args, out string sqlCount, out string sqlPage) => throw new NotImplementedException(); public void InsertBulk(IEnumerable pocos) => throw new NotImplementedException(); public void InsertBatch(IEnumerable pocos, BatchOptions options = null) => throw new NotImplementedException(); public Tuple, List> FetchMultiple(string sql, params object[] args) => throw new NotImplementedException(); public Tuple, List, List> FetchMultiple(string sql, params object[] args) => throw new NotImplementedException(); public Tuple, List, List, List> FetchMultiple(string sql, params object[] args) => throw new NotImplementedException(); public Tuple, List> FetchMultiple(Sql sql) => throw new NotImplementedException(); public Tuple, List, List> FetchMultiple(Sql sql) => throw new NotImplementedException(); public Tuple, List, List, List> FetchMultiple(Sql sql) => throw new NotImplementedException(); public IDatabase OpenSharedConnection(OpenConnectionOptions? options = null) => throw new NotImplementedException(); public Task OpenSharedConnectionAsync(CancellationToken cancellationToken = default) => throw new NotImplementedException(); public Task OpenSharedConnectionAsync(OpenConnectionOptions options, CancellationToken cancellationToken = default) => throw new NotImplementedException(); public Task CloseSharedConnectionAsync() => throw new NotImplementedException(); public Task GetTransactionAsync() => throw new NotImplementedException(); public Task GetTransactionAsync(IsolationLevel isolationLevel) => throw new NotImplementedException(); public Task BeginTransactionAsync(CancellationToken cancellationToken = default) => throw new NotImplementedException(); public Task BeginTransactionAsync(IsolationLevel isolationLevel, CancellationToken cancellationToken = default) => throw new NotImplementedException(); public Task AbortTransactionAsync(CancellationToken cancellationToken = default) => throw new NotImplementedException(); public Task CompleteTransactionAsync(CancellationToken cancellationToken = default) => throw new NotImplementedException(); public ValueTask DisposeAsync() => throw new NotImplementedException(); /// /// Represents a database operation. /// public class Operation { public Operation(string text) => Text = text; public Operation(string text, string sql) : this(text) => Sql = sql; public Operation(string text, string sql, params object[] args) : this(text, sql) => Args = args; /// /// Gets the operation text. /// public string Text { get; } /// /// Gets the operation Sql statement. /// public string Sql { get; } /// /// Gets the operation Sql arguments. /// public object[] Args { get; } } }