1   /*
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2026, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v2.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  
15  package ch.qos.logback.core.pattern;
16  
17  import java.util.HashMap;
18  import java.util.Map;
19  import java.util.function.Supplier;
20  
21  import org.junit.jupiter.api.Assertions;
22  import org.junit.jupiter.api.BeforeEach;
23  import org.junit.jupiter.api.Test;
24  
25  import ch.qos.logback.core.Context;
26  import ch.qos.logback.core.ContextBase;
27  import ch.qos.logback.core.pattern.parser.Node;
28  import ch.qos.logback.core.pattern.parser.Parser;
29  import ch.qos.logback.core.spi.ContextAware;
30  import ch.qos.logback.core.spi.LifeCycle;
31  import ch.qos.logback.core.spi.ScanException;
32  
33  // inspired by ch.qos.logback.core.pattern.parser.CompilerTest
34  public class ConverterUtilTest {
35  
36      Map<String, Supplier<DynamicConverter>> converterMap = new HashMap<>();
37      Context context = new ContextBase();
38  
39      @BeforeEach
40      public void setUp() {
41          converterMap.put("OTT", Converter123::new);
42          converterMap.put("hello", ConverterHello::new);
43          converterMap.putAll(Parser.DEFAULT_COMPOSITE_CONVERTER_MAP);
44      }
45  
46      @Test
47      public void contextAndStartTest() throws ScanException {
48          testContextAndStart("hi %hello");
49          testContextAndStart("hi %(%hello)");
50          testContextAndStart("hi %(abc %(%hello))");
51  
52      }
53  
54      private void testContextAndStart(String pattern) throws ScanException {
55          Parser<Object> p = new Parser<Object>(pattern);
56          p.setContext(context);
57          Node t = p.parse();
58          Converter<Object> head = p.compile(t, converterMap);
59          ConverterUtil.setContextForConverters(context, head);
60          checkContext(head);
61  
62          ConverterUtil.startConverters(head);
63          checkStart(head);
64      }
65  
66      private void checkStart(Converter<Object> head) {
67          Converter<Object> c = head;
68          while (c != null) {
69              if (c instanceof LifeCycle) {
70                  LifeCycle ca = (LifeCycle) c;
71                  Assertions.assertTrue(ca.isStarted());
72              }
73              if (c instanceof CompositeConverter) {
74                  CompositeConverter<Object> cc = (CompositeConverter<Object>) c;
75                  Converter<Object> childConverter = cc.childConverter;
76                  checkStart(childConverter);
77              }
78              c = c.getNext();
79          }
80  
81      }
82  
83      void checkContext(Converter<Object> head) {
84          Converter<Object> c = head;
85          while (c != null) {
86              if (c instanceof ContextAware) {
87                  ContextAware ca = (ContextAware) c;
88                  Assertions.assertNotNull(ca.getContext());
89              }
90              if (c instanceof CompositeConverter) {
91                  CompositeConverter<Object> cc = (CompositeConverter<Object>) c;
92                  Converter<Object> childConverter = cc.childConverter;
93                  checkContext(childConverter);
94              }
95              c = c.getNext();
96          }
97      }
98  
99  }