1   /* Copyright 2002-2025 CS GROUP
2    * Licensed to CS GROUP (CS) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * CS licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.orekit.propagation.events;
18  
19  import java.util.Collections;
20  import java.util.NoSuchElementException;
21  
22  import org.junit.jupiter.api.Assertions;
23  import org.junit.jupiter.api.BeforeEach;
24  import org.junit.jupiter.api.Test;
25  import org.mockito.Mockito;
26  import org.orekit.propagation.SpacecraftState;
27  import org.orekit.propagation.events.handlers.EventHandler;
28  import org.orekit.propagation.events.intervals.AdaptableInterval;
29  import org.orekit.time.AbsoluteDate;
30  
31  /**
32   * Unit tests for {@link BooleanDetector#orCombine(EventDetector...)}.
33   *
34   * @author Evan Ward
35   */
36  public class OrDetectorTest {
37  
38      /** first operand. */
39      private MockDetector a;
40      /** second operand. */
41      private MockDetector b;
42      /** null */
43      private SpacecraftState s;
44      /** subject under test */
45      private BooleanDetector or;
46  
47      /** create subject under test and dependencies. */
48      @BeforeEach
49      public void setUp() {
50          a = new MockDetector();
51          b = new MockDetector();
52          s = null;
53          or = BooleanDetector.orCombine(a, b);
54      }
55  
56      /**
57       * check {@link BooleanDetector#g(SpacecraftState)}.
58       */
59      @Test
60      public void testG() {
61          // test zero cases
62          a.g = b.g = 0.0;
63          Assertions.assertEquals(0.0, or.g(s), 0);
64          a.g = -1;
65          b.g = 0;
66          Assertions.assertEquals(0.0, or.g(s), 0);
67          a.g = 0;
68          b.g = -1;
69          Assertions.assertEquals(0.0, or.g(s), 0);
70  
71          // test negative cases
72          a.g = -1;
73          b.g = -1;
74          Assertions.assertTrue(or.g(s) < 0, "negative");
75  
76          // test positive cases
77          a.g = 0;
78          b.g = 1;
79          Assertions.assertTrue(or.g(s) > 0, "positive");
80          a.g = 1;
81          b.g = -1;
82          Assertions.assertTrue(or.g(s) > 0, "positive");
83          a.g = 1;
84          b.g = 0;
85          Assertions.assertTrue(or.g(s) > 0, "positive");
86          a.g = -1;
87          b.g = 1;
88          Assertions.assertTrue(or.g(s) > 0, "positive");
89          a.g = 1;
90          b.g = 1;
91          Assertions.assertTrue(or.g(s) > 0, "positive");
92  
93      }
94  
95      /**
96       * check when there is numeric cancellation between the two g values.
97       */
98      @Test
99      public void testCancellation() {
100         a.g = -1e-10;
101         b.g = -1e10;
102         Assertions.assertTrue(or.g(s) < 0, "negative");
103         a.g = -1e10;
104         b.g = -1e-10;
105         Assertions.assertTrue(or.g(s) < 0, "negative");
106         a.g = -1e10;
107         b.g = 1e-10;
108         Assertions.assertTrue(or.g(s) > 0, "positive");
109         a.g = 1e-10;
110         b.g = -1e10;
111         Assertions.assertTrue(or.g(s) > 0, "positive");
112         a.g = 1e10;
113         b.g = -1e-10;
114         Assertions.assertTrue(or.g(s) > 0, "positive");
115         a.g = -1e-10;
116         b.g = 1e10;
117         Assertions.assertTrue(or.g(s) > 0, "positive");
118     }
119 
120     /**
121      * Check wrapped detectors are initialized.
122      */
123     @Test
124     public void testInit() {
125         // setup
126         EventDetector a = Mockito.mock(EventDetector.class);
127         Mockito.when(a.getMaxCheckInterval()).thenReturn(AdaptableInterval.of(AbstractDetector.DEFAULT_MAX_CHECK));
128         Mockito.when(a.getThreshold()).thenReturn(AbstractDetector.DEFAULT_THRESHOLD);
129         EventDetector b = Mockito.mock(EventDetector.class);
130         Mockito.when(b.getMaxCheckInterval()).thenReturn(AdaptableInterval.of(AbstractDetector.DEFAULT_MAX_CHECK));
131         Mockito.when(b.getThreshold()).thenReturn(AbstractDetector.DEFAULT_THRESHOLD);
132         EventHandler c = Mockito.mock(EventHandler.class);
133         BooleanDetector or = BooleanDetector.orCombine(a, b).withHandler(c);
134         AbsoluteDate t = AbsoluteDate.CCSDS_EPOCH;
135         s = Mockito.mock(SpacecraftState.class);
136         Mockito.when(s.getDate()).thenReturn(t.shiftedBy(60.0));
137 
138         // action
139         or.init(s, t);
140 
141         // verify
142         Assertions.assertEquals(2, or.getDetectors().size());
143         Mockito.verify(a).init(s, t);
144         Mockito.verify(b).init(s, t);
145         Mockito.verify(c).init(s, t, or);
146     }
147 
148     /** check when no operands are passed to the constructor. */
149     @Test
150     public void testZeroDetectors() {
151         // action
152         try {
153             BooleanDetector.orCombine(Collections.emptyList());
154             Assertions.fail("Expected Exception");
155         } catch (NoSuchElementException e) {
156             // expected
157         }
158     }
159 
160     /** Mock detector to set the g function to arbitrary values. */
161     private static class MockDetector implements EventDetector {
162 
163         /** value to return from {@link #g(SpacecraftState)}. */
164         public double g = 0;
165 
166         @Override
167         public void init(SpacecraftState s0, AbsoluteDate t) {
168 
169         }
170 
171         @Override
172         public double g(SpacecraftState s) {
173             return this.g;
174         }
175 
176         @Override
177         public EventDetectionSettings getDetectionSettings() {
178             return EventDetectionSettings.getDefaultEventDetectionSettings();
179         }
180 
181         @Override
182         public EventHandler getHandler() {
183             return (state, detector, increasing) -> null;
184         }
185     }
186 }