content: /*
   *  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.
   */
  package org.apache.causeway.commons.internal.context;
  
  import org.junit.jupiter.api.AfterEach;
  import org.junit.jupiter.api.BeforeEach;
  import org.junit.jupiter.api.Disabled;
  import org.junit.jupiter.api.Test;
  
  import static org.junit.jupiter.api.Assertions.assertFalse;
  import static org.junit.jupiter.api.Assertions.assertNotNull;
  import static org.junit.jupiter.api.Assertions.assertNull;
  import static org.junit.jupiter.api.Assertions.assertThrows;
  import static org.junit.jupiter.api.Assertions.assertTrue;
  
  @Disabled("some tests fail to run on eclipse -> "
          + "java.lang.ClassNotFoundException: org.junit.platform.commons.logging.LogRecordListener")
  class ContextTest {
  
      public static class AClass {
          String name;
      }
  
      @BeforeEach
      void beforeEach() {
          _Context.clear();
      }
  
      @AfterEach
      void afterEach() {
          _Context.clear();
      }
  
      @Test
      void precondition() {
          final Class<AClass> type = AClass.class;
  
          final Object actual = _Context.getIfAny(type); 
          assertNull(actual, "pre-condition: context is expected to be empty");
      }
  
      @Test
      void testPutSingleton() {
  
          final Class<AClass> type = AClass.class;
          final AClass singleton = new AClass();
  
          _Context.putSingleton(type, singleton);
  
          final Object actual = _Context.getIfAny(type);
          assertTrue(singleton==actual, "singleton on context is expected to be the same as the 'local' instance");
  
          assertThrows(IllegalStateException.class, 
                  ()->{_Context.putSingleton(type, singleton);},
                  "expected to throw: you cannot override a singleton that is already on the context");
  
          assertThrows(NullPointerException.class, 
                  ()->{_Context.putSingleton(type, null);},
                  "expected to throw: you cannot put null references onto the context");
      }
  
      @Test
      void testPutWithOverride() {
  
          final Class<AClass> type = AClass.class;
          final AClass instance1 = new AClass();
          final AClass instance2 = new AClass();
  
          {
              final boolean success = _Context.put(type, instance1, true);
              assertTrue(success, "expected: successful put");
  
              final Object actual = _Context.getIfAny(type);
              assertTrue(instance1==actual, "singleton on context is expected to be the same as the 'local' instance1");
          }
  
          {
              final boolean success = _Context.put(type, instance2, true);
              assertTrue(success, "expected: successful put");
  
              final Object actual = _Context.getIfAny(type);
              assertTrue(instance2==actual, "singleton on context is expected to be the same as the 'local' instance2");
          }
  
          assertThrows(NullPointerException.class, 
                  ()->{_Context.put(type, null, true);},
                  "expected to throw: you cannot put null references onto the context");
  
      }
  
      @Test
      void testPutWithoutOverride() {
  
          final Class<AClass> type = AClass.class;
          final AClass instance1 = new AClass();
          final AClass instance2 = new AClass();
  
          {
              final boolean success = _Context.put(type, instance1, false);
              assertTrue(success, "expected: successful put");
  
              final Object actual = _Context.getIfAny(type);
              assertTrue(instance1==actual, "singleton on context is expected to be the same as the 'local' instance1");
          }
  
          {
              final boolean success = _Context.put(type, instance2, false);
              assertFalse(success, "expected: failed put");
  
              final Object actual = _Context.getIfAny(type);
              assertTrue(instance1==actual, "singleton on context is expected to be the same as the 'local' instance1");
          }
  
          assertThrows(NullPointerException.class, 
                  ()->{_Context.put(type, null, false);},
                  "expected to throw: you cannot put null references onto the context");
  
      }
  
      @Test
      void testComputeIfAbsent() {
  
          final Class<AClass> type = AClass.class;
          final AClass instance1 = new AClass();
          final AClass instance2 = new AClass();
  
          _Context.computeIfAbsent(type, ()->instance1);
  
          {
              final Object actual = _Context.getIfAny(type);
              assertTrue(instance1==actual, "singleton on context is expected to be the same as the 'local' instance1");
          }
  
          _Context.computeIfAbsent(type, ()->instance2); // expected: this call does nothing
  
          { 
              final Object actual = _Context.getIfAny(type);
              assertTrue(instance1==actual, "singleton on context is expected to be the same as the 'local' instance1");
          }
  
      }
  
      @Test
      void testGetOrElse() {
  
          final Class<AClass> type = AClass.class;
          final AClass singleton = new AClass();
          final AClass fallback = new AClass();
  
          { 
              final Object actual = _Context.getOrElse(type, ()->fallback);
              assertTrue(fallback==actual, "singleton on context is expected to be the same as the 'local' fallback");
          }
  
          _Context.putSingleton(type, singleton);
  
          { 
              final Object actual = _Context.getOrElse(type, ()->fallback);
              assertTrue(singleton==actual, "singleton on context is expected to be the same as the 'local' singleton");
          }
      }
  
      @Test
      void testGetOrThrow() {
  
          final Class<AClass> type = AClass.class;
          final AClass singleton = new AClass();
  
          assertThrows(IllegalStateException.class, 
                  ()->{_Context.getElseThrow(type, IllegalStateException::new);},
                  "expected to throw: no singleton on context that matches the given type");
  
          _Context.putSingleton(type, singleton);
  
          final Object actual = _Context.getElseThrow(type, IllegalStateException::new);
          assertTrue(singleton==actual, "singleton on context is expected to be the same as the 'local' singleton");
      }
  
      @Test
      void testGetDefaultClassLoader() {
          assertNotNull(_Context.getDefaultClassLoader(), "expected: even an empty context should provide a non-empty default");
      }
  
      @Test
      void testSetDefaultClassLoaderWithOverride() {
          assertThrows(NullPointerException.class, 
                  ()->{_Context.setDefaultClassLoader(null, true);},
                  "expected to throw: you cannot put null references onto the context");
  
          _Context.setDefaultClassLoader(AClass.class.getClassLoader(), true);
  
          final Object actual = _Context.getDefaultClassLoader();
          assertTrue(AClass.class.getClassLoader()==actual, "singleton on context is expected to be the same as the 'local' singleton");
      }
  
      @Test
      void testSetDefaultClassLoaderWithoutOverride() {
  
          assertThrows(NullPointerException.class, 
                  ()->{_Context.setDefaultClassLoader(null, false);},
                  "expected to throw: you cannot put null references onto the context");
  
          _Context.setDefaultClassLoader(AClass.class.getClassLoader(), false);
  
          final Object actual = _Context.getDefaultClassLoader();
          assertTrue(AClass.class.getClassLoader()==actual, "singleton on context is expected to be the same as the 'local' singleton");
      }
  
      @Test
      void testLoadClass() {
          assertThrows(ClassNotFoundException.class, 
                  ()->_Context.loadClass(AClass.class.getName()));
      }
  
      @Test
      void testLoadClassAndInitialize() {
          assertThrows(ClassNotFoundException.class, 
                  ()->_Context.loadClassAndInitialize(AClass.class.getName()));
      }
  
  }
  