001package arez.persist.runtime;
002
003import java.lang.reflect.Field;
004import javax.annotation.Nonnull;
005import javax.annotation.Nullable;
006
007/**
008 * Utility class for interacting with ArezPersist config settings in tests.
009 */
010@SuppressWarnings( "WeakerAccess" )
011@GwtIncompatible
012public final class ArezPersistTestUtil
013{
014  private ArezPersistTestUtil()
015  {
016  }
017
018  /**
019   * Interface to intercept log messages emitted by ArezPersist runtime.
020   */
021  public interface Logger
022  {
023    void log( @Nonnull String message, @Nullable Throwable throwable );
024  }
025
026  /**
027   * Reset the state of ArezPersist config to either production or development state.
028   *
029   * @param production true to set it to production environment configuration, false to set it to development environment config.
030   */
031  public static void resetConfig( final boolean production )
032  {
033    if ( ArezPersistConfig.isProductionEnvironment() )
034    {
035      throw new IllegalStateException( "Unable to reset config as ArezPersist is in production mode" );
036    }
037
038    if ( production )
039    {
040      noCheckApiInvariants();
041    }
042    else
043    {
044      checkApiInvariants();
045    }
046    enableApplicationStore();
047    resetState();
048  }
049
050  /**
051   * Reset the state of ArezPersist.
052   * This occasionally needs to be invoked after changing configuration settings in tests.
053   */
054  public static void resetState()
055  {
056    setLogger( null );
057    Registry.reset();
058  }
059
060  /**
061   * Specify logger to use to capture logging in tests
062   *
063   * @param logger the logger.
064   */
065  public static void setLogger( @Nullable final Logger logger )
066  {
067    if ( ArezPersistConfig.isProductionEnvironment() )
068    {
069      throw new IllegalStateException( "Unable to call ArezTestUtil.setLogger() as ArezPersist is in production mode" );
070    }
071
072    final LogUtil.ProxyLogger proxyLogger = (LogUtil.ProxyLogger) LogUtil.getLogger();
073    proxyLogger.setLogger( null == logger ? null : logger::log );
074  }
075
076  /**
077   * Set the `arez.persist.enable_application_store` setting to true.
078   */
079  public static void enableApplicationStore()
080  {
081    setEnableApplicationStore( true );
082  }
083
084  /**
085   * Set the `arez.persist.enable_application_store` setting to false.
086   */
087  public static void disableApplicationStore()
088  {
089    setEnableApplicationStore( false );
090  }
091
092  /**
093   * Configure the `arez.persist.enable_application_store` setting.
094   *
095   * @param setting the setting.
096   */
097  private static void setEnableApplicationStore( final boolean setting )
098  {
099    setConstant( "ENABLE_APPLICATION_STORE", setting );
100  }
101
102  /**
103   * Set the `arez.persist.check_api_invariants` setting to true.
104   */
105  public static void checkApiInvariants()
106  {
107    setCheckApiInvariants( true );
108  }
109
110  /**
111   * Set the `arez.persist.check_api_invariants` setting to false.
112   */
113  public static void noCheckApiInvariants()
114  {
115    setCheckApiInvariants( false );
116  }
117
118  /**
119   * Configure the `arez.persist.check_api_invariants` setting.
120   *
121   * @param setting the setting.
122   */
123  private static void setCheckApiInvariants( final boolean setting )
124  {
125    setConstant( "CHECK_API_INVARIANTS", setting );
126  }
127
128  /**
129   * Set the specified field name on ArezPersistConfig.
130   */
131  @SuppressWarnings( "NonJREEmulationClassesInClientCode" )
132  private static void setConstant( @Nonnull final String fieldName, final boolean value )
133  {
134    if ( ArezPersistConfig.isProductionEnvironment() )
135    {
136      throw new IllegalStateException( "Unable to change constant " + fieldName +
137                                       " as ArezPersist is in production mode" );
138    }
139    else
140    {
141      try
142      {
143        final Field field = ArezPersistConfig.class.getDeclaredField( fieldName );
144        field.setAccessible( true );
145        field.set( null, value );
146      }
147      catch ( final NoSuchFieldException | IllegalAccessException e )
148      {
149        throw new IllegalStateException( "Unable to change constant " + fieldName, e );
150      }
151    }
152  }
153}