text:
package org.stajistics.configuration;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.fail;

import java.util.HashMap;
import java.util.Map;

import org.jmock.Expectations;
import org.junit.Before;
import org.junit.Test;
import org.stajistics.AbstractStajisticsTestCase;
import org.stajistics.DefaultStatsKeyFactory;
import org.stajistics.SimpleStatsKey;
import org.stajistics.StatsKey;
import org.stajistics.StatsKeyFactory;
import org.stajistics.event.EventManager;
import org.stajistics.event.EventType;
import org.stajistics.session.DefaultSessionFactory;
import org.stajistics.session.recorder.DefaultDataRecorderFactory;
import org.stajistics.tracker.span.TimeDurationTracker;

/**
 *
 * @author The Stajistics Project
 */
public class DefaultStatsConfigManagerTest extends AbstractStajisticsTestCase {

    private EventManager mockEventManager;
    private StatsKeyFactory mockKeyFactory;

    private DefaultStatsConfigManager configManager;

    @Before
    public void setUp() {
        mockEventManager = mockery.mock(EventManager.class);
        mockKeyFactory = new DefaultStatsKeyFactory(); // TODO: actually mock this

        configManager = new DefaultStatsConfigManager(mockEventManager, mockKeyFactory);
    }

    private StatsConfig createConfig() {
        return new DefaultStatsConfig(true,
                                      TimeDurationTracker.FACTORY,
                                      DefaultSessionFactory.getInstance(),
                                      DefaultDataRecorderFactory.getInstance(),
                                      "test",
                                      null);
    }

    private StatsKey[] createKeyHierarchy() {
        return new StatsKey[] {
            new SimpleStatsKey(null, "test", mockKeyFactory),
            new SimpleStatsKey(null, "test.child", mockKeyFactory),
            new SimpleStatsKey(null, "test.child.grandchild", mockKeyFactory),
            new SimpleStatsKey(null, "test.child.grandchild.greatgrandchild", mockKeyFactory)
        };
    }

    @Test
    public void testConstructWithConfigs() {

        final StatsKey[] keys = createKeyHierarchy();

        StatsConfig rootConfig = createConfig();
        final StatsConfig config0 = createConfig();
        final StatsConfig config1 = createConfig();
        final StatsConfig config2 = createConfig();
        final StatsConfig config3 = createConfig();

        Map<String,StatsConfig> configMap = new HashMap<String,StatsConfig>();

        configMap.put(keys[0].getName(), config0);
        configMap.put(keys[1].getName(), config1);
        configMap.put(keys[2].getName(), config2);
        configMap.put(keys[3].getName(), config3);

        mockery.checking(new Expectations() {{
            one(mockEventManager).fireEvent(with(EventType.CONFIG_CREATED),
                                            with(keys[0]),
                                            with(config0));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_CREATED),
                                            with(keys[1]),
                                            with(config1));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_CREATED),
                                            with(keys[2]),
                                            with(config2));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_CREATED),
                                            with(keys[3]),
                                            with(config3));
        }});

        configManager = new DefaultStatsConfigManager(mockEventManager,
                                                      mockKeyFactory,
                                                      rootConfig,
                                                      configMap);

        assertSame(rootConfig, configManager.getRootConfig());
        assertSame(config0, configManager.getConfig(keys[0]));
        assertSame(config1, configManager.getConfig(keys[1]));
        assertSame(config2, configManager.getConfig(keys[2]));
        assertSame(config3, configManager.getConfig(keys[3]));
    }

    @Test
    public void testGetRootConfigNotNull() {
        assertNotNull(configManager.getRootConfig());
    }

    @Test
    public void testSetAndGetRootConfig() {

        final StatsConfig config = createConfig();

        configManager.setRootConfig(config);
        assertSame(config, configManager.getRootConfig());
    }

    @Test
    public void testSetRootConfigWithNull() {
        configManager.setRootConfig(null);
        assertNotNull(configManager.getRootConfig());
    }

    @Test
    public void testSetConfigWithNullKey() {
        try {
            configManager.setConfig((StatsKey)null, createConfig());
            fail("Allowed setConfig with null key");
        } catch (NullPointerException npe) {
            // expected
        }
    }

    @Test
    public void testSetConfigWithNullConfig() {
        mockery.checking(new Expectations() {{
            ignoring(mockEventManager);
        }});

        StatsKey key = new SimpleStatsKey(null, "test", mockKeyFactory);

        StatsConfig rootConfig = configManager.getRootConfig();

        configManager.setConfig(key, null);
        assertSame(rootConfig, configManager.getRootConfig());
        assertSame(configManager.getRootConfig(), configManager.getConfig(key));

        key = new SimpleStatsKey(null, "test.child", mockKeyFactory);
        configManager.setConfig(key, null);
        assertSame(rootConfig, configManager.getRootConfig());
        assertSame(configManager.getRootConfig(), configManager.getConfig(key));

        key = new SimpleStatsKey(null, "test.child.grandchild", mockKeyFactory);
        configManager.setConfig(key, null);
        assertSame(rootConfig, configManager.getRootConfig());
        assertSame(configManager.getRootConfig(), configManager.getConfig(key));
    }

    @Test
    public void testSetConfigAscending() {

        final StatsKey[] keys = createKeyHierarchy();

        final StatsConfig rootConfig = configManager.getRootConfig();
        final StatsConfig config0 = createConfig();
        final StatsConfig config1 = createConfig();
        final StatsConfig config2 = createConfig();
        final StatsConfig config3 = createConfig();

        mockery.checking(new Expectations() {{
            one(mockEventManager).fireEvent(with(EventType.CONFIG_CREATED),
                                            with(keys[0]),
                                            with(config0));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_CREATED),
                                            with(keys[1]),
                                            with(config1));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_CREATED),
                                            with(keys[2]),
                                            with(config2));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_CREATED),
                                            with(keys[3]),
                                            with(config3));
        }});

        // Level 0
        assertNull(configManager.getConfig(keys[0]));
        configManager.setConfig(keys[0], config0);
        assertSame(rootConfig, configManager.getRootConfig());
        assertSame(config0, configManager.getConfig(keys[0]));

        // Level 1
        assertNull(configManager.getConfig(keys[1]));
        configManager.setConfig(keys[1], config1);
        assertSame(rootConfig, configManager.getRootConfig());
        assertSame(config0, configManager.getConfig(keys[0]));
        assertSame(config1, configManager.getConfig(keys[1]));

        // Level 2
        assertNull(configManager.getConfig(keys[2]));
        configManager.setConfig(keys[2], config2);
        assertSame(rootConfig, configManager.getRootConfig());
        assertSame(config0, configManager.getConfig(keys[0]));
        assertSame(config1, configManager.getConfig(keys[1]));
        assertSame(config2, configManager.getConfig(keys[2]));

        // Level 3
        assertNull(configManager.getConfig(keys[3]));
        configManager.setConfig(keys[3], config3);
        assertSame(rootConfig, configManager.getRootConfig());
        assertSame(config0, configManager.getConfig(keys[0]));
        assertSame(config1, configManager.getConfig(keys[1]));
        assertSame(config2, configManager.getConfig(keys[2]));
        assertSame(config3, configManager.getConfig(keys[3]));
    }

    @Test
    public void testSetConfigDescending() {

        final StatsKey[] keys = createKeyHierarchy();

        final StatsConfig rootConfig = configManager.getRootConfig();
        final StatsConfig config0 = createConfig();
        final StatsConfig config1 = createConfig();
        final StatsConfig config2 = createConfig();
        final StatsConfig config3 = createConfig();

        mockery.checking(new Expectations() {{
            one(mockEventManager).fireEvent(with(EventType.CONFIG_CREATED),
                                            with(keys[0]),
                                            with(rootConfig));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_CREATED),
                                            with(keys[1]),
                                            with(rootConfig));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_CREATED),
                                            with(keys[2]),
                                            with(rootConfig));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_CREATED),
                                            with(keys[3]),
                                            with(config3));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_CHANGED),
                                            with(keys[2]),
                                            with(config2));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_CHANGED),
                                            with(keys[1]),
                                            with(config1));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_CHANGED),
                                            with(keys[0]),
                                            with(config0));
        }});

        // Level 3
        configManager.setConfig(keys[3], config3);
        assertSame(config3, configManager.getConfig(keys[3]));
        assertSame(rootConfig, configManager.getConfig(keys[2]));
        assertSame(rootConfig, configManager.getConfig(keys[1]));
        assertSame(rootConfig, configManager.getConfig(keys[0]));
        assertSame(rootConfig, configManager.getRootConfig());

        // Level 2
        configManager.setConfig(keys[2], config2);
        assertSame(config3, configManager.getConfig(keys[3]));
        assertSame(config2, configManager.getConfig(keys[2]));
        assertSame(rootConfig, configManager.getConfig(keys[1]));
        assertSame(rootConfig, configManager.getConfig(keys[0]));
        assertSame(rootConfig, configManager.getRootConfig());

        // Level 1
        configManager.setConfig(keys[1], config1);
        assertSame(config3, configManager.getConfig(keys[3]));
        assertSame(config2, configManager.getConfig(keys[2]));
        assertSame(config1, configManager.getConfig(keys[1]));
        assertSame(rootConfig, configManager.getConfig(keys[0]));
        assertSame(rootConfig, configManager.getRootConfig());

        // Level 0
        configManager.setConfig(keys[0], config0);
        assertSame(config3, configManager.getConfig(keys[3]));
        assertSame(config2, configManager.getConfig(keys[2]));
        assertSame(config1, configManager.getConfig(keys[1]));
        assertSame(config0, configManager.getConfig(keys[0]));
        assertSame(rootConfig, configManager.getRootConfig());
    }

    @Test
    public void testGetOrCreateRootConfigAscending() {

        final StatsKey[] keys = createKeyHierarchy();

        final StatsConfig rootConfig = configManager.getRootConfig();

        mockery.checking(new Expectations() {{
            one(mockEventManager).fireEvent(with(EventType.CONFIG_CREATED),
                                            with(keys[0]),
                                            with(rootConfig));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_CREATED),
                                            with(keys[1]),
                                            with(rootConfig));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_CREATED),
                                            with(keys[2]),
                                            with(rootConfig));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_CREATED),
                                            with(keys[3]),
                                            with(rootConfig));
        }});

        assertSame(rootConfig, configManager.getOrCreateConfig(keys[0]));
        assertSame(rootConfig, configManager.getOrCreateConfig(keys[1]));
        assertSame(rootConfig, configManager.getOrCreateConfig(keys[2]));
        assertSame(rootConfig, configManager.getOrCreateConfig(keys[3]));
    }

    @Test
    public void testGetOrCreateRootConfigDescending() {

        final StatsKey[] keys = createKeyHierarchy();

        final StatsConfig rootConfig = configManager.getRootConfig();

        mockery.checking(new Expectations() {{
            one(mockEventManager).fireEvent(with(EventType.CONFIG_CREATED),
                                            with(keys[0]),
                                            with(rootConfig));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_CREATED),
                                            with(keys[1]),
                                            with(rootConfig));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_CREATED),
                                            with(keys[2]),
                                            with(rootConfig));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_CREATED),
                                            with(keys[3]),
                                            with(rootConfig));
        }});

        assertSame(rootConfig, configManager.getOrCreateConfig(keys[3]));
        assertSame(rootConfig, configManager.getOrCreateConfig(keys[2]));
        assertSame(rootConfig, configManager.getOrCreateConfig(keys[1]));
        assertSame(rootConfig, configManager.getOrCreateConfig(keys[0]));
    }

    @Test
    public void testGetOrCreate_GetLevel1_SetLevel2_GetLevel3_SetLevel4() {
        mockery.checking(new Expectations() {{
            ignoring(mockEventManager);
        }});

        StatsKey[] keys = createKeyHierarchy();

        StatsConfig rootConfig = configManager.getRootConfig();

        // Get level 0
        assertSame(rootConfig, configManager.getOrCreateConfig(keys[0]));
        assertSame(rootConfig, configManager.getRootConfig());

        // Set level 1
        StatsConfig config1 = createConfig();
        configManager.setConfig(keys[1], config1);
        assertSame(config1, configManager.getOrCreateConfig(keys[1]));
        assertSame(rootConfig, configManager.getOrCreateConfig(keys[0]));
        assertSame(rootConfig, configManager.getRootConfig());

        // Get level 2
        assertSame(config1, configManager.getOrCreateConfig(keys[2]));
        assertSame(config1, configManager.getOrCreateConfig(keys[1]));
        assertSame(rootConfig, configManager.getOrCreateConfig(keys[0]));
        assertSame(rootConfig, configManager.getRootConfig());

        // Set level 3
        StatsConfig config3 = createConfig();
        configManager.setConfig(keys[3], config3);
        assertSame(config3, configManager.getOrCreateConfig(keys[3]));
        assertSame(config1, configManager.getOrCreateConfig(keys[2]));
        assertSame(config1, configManager.getOrCreateConfig(keys[1]));
        assertSame(rootConfig, configManager.getOrCreateConfig(keys[0]));
        assertSame(rootConfig, configManager.getRootConfig());
    }

    @Test
    public void testGetOrCreate_SetLevel1_GetLevel2_SetLevel3_GetLevel4() {
        mockery.checking(new Expectations() {{
            ignoring(mockEventManager);
        }});

        StatsKey[] keys = createKeyHierarchy();

        StatsConfig rootConfig = configManager.getRootConfig();

        // Set level 0
        StatsConfig config0 = createConfig();
        configManager.setConfig(keys[0], config0);
        assertSame(config0, configManager.getOrCreateConfig(keys[0]));
        assertSame(rootConfig, configManager.getRootConfig());

        // Get level 1
        assertSame(config0, configManager.getOrCreateConfig(keys[1]));
        assertSame(config0, configManager.getOrCreateConfig(keys[0]));
        assertSame(rootConfig, configManager.getRootConfig());

        // Set level 2
        StatsConfig config2 = createConfig();
        configManager.setConfig(keys[2], config2);
        assertSame(config2, configManager.getOrCreateConfig(keys[2]));
        assertSame(config0, configManager.getOrCreateConfig(keys[1]));
        assertSame(config0, configManager.getOrCreateConfig(keys[0]));
        assertSame(rootConfig, configManager.getRootConfig());

        // Get level 3
        assertSame(config2, configManager.getOrCreateConfig(keys[3]));
        assertSame(config2, configManager.getOrCreateConfig(keys[2]));
        assertSame(config0, configManager.getOrCreateConfig(keys[1]));
        assertSame(config0, configManager.getOrCreateConfig(keys[0]));
        assertSame(rootConfig, configManager.getRootConfig());
    }

    @Test
    public void testGetOrCreate_GetLevel4_SetLevel3_GetLevel2_SetLevel1() {
        mockery.checking(new Expectations() {{
            ignoring(mockEventManager);
        }});

        StatsKey[] keys = createKeyHierarchy();

        StatsConfig rootConfig = configManager.getRootConfig();

        // Get level 3
        assertSame(rootConfig, configManager.getOrCreateConfig(keys[3]));

        // Set level 2
        StatsConfig config2 = createConfig();
        configManager.setConfig(keys[2], config2);
        assertSame(config2, configManager.getOrCreateConfig(keys[3]));
        assertSame(config2, configManager.getOrCreateConfig(keys[2]));

        // Get level 1
        assertSame(rootConfig, configManager.getOrCreateConfig(keys[1]));
        assertSame(config2, configManager.getOrCreateConfig(keys[3]));
        assertSame(config2, configManager.getOrCreateConfig(keys[2]));

        // Set level 0
        StatsConfig config0 = createConfig();
        configManager.setConfig(keys[0], config0);
        assertSame(config0, configManager.getOrCreateConfig(keys[0]));
        assertSame(config0, configManager.getOrCreateConfig(keys[1]));
        assertSame(config2, configManager.getOrCreateConfig(keys[2]));
        assertSame(config2, configManager.getOrCreateConfig(keys[3]));
    }

    @Test
    public void testGetOrCreate_SetLevel4_GetLevel3_SetLevel2_GetLevel1() {
        mockery.checking(new Expectations() {{
            ignoring(mockEventManager);
        }});

        StatsKey[] keys = createKeyHierarchy();

        StatsConfig rootConfig = configManager.getRootConfig();

        // Set level 3
        StatsConfig config3 = createConfig();
        configManager.setConfig(keys[3], config3);
        assertSame(config3, configManager.getOrCreateConfig(keys[3]));

        // Get level 2
        assertSame(rootConfig, configManager.getConfig(keys[2]));
        assertSame(config3, configManager.getOrCreateConfig(keys[3]));

        // Set level 1
        StatsConfig config1 = createConfig();
        configManager.setConfig(keys[1], config1);
        assertSame(config1, configManager.getOrCreateConfig(keys[1]));
        assertSame(config1, configManager.getOrCreateConfig(keys[2]));
        assertSame(config3, configManager.getOrCreateConfig(keys[3]));

        // Get level 0
        assertSame(rootConfig, configManager.getOrCreateConfig(keys[0]));
        assertSame(config1, configManager.getOrCreateConfig(keys[1]));
        assertSame(config1, configManager.getOrCreateConfig(keys[2]));
        assertSame(config3, configManager.getOrCreateConfig(keys[3]));
    }

    @Test
    public void testGetConfig() {
        mockery.checking(new Expectations() {{
            exactly(4).of(mockEventManager).fireEvent(with(EventType.CONFIG_CREATED),
                                                      with(any(StatsKey.class)),
                                                      with(any(StatsConfig.class)));
        }});

        StatsKey[] keys = createKeyHierarchy();

        configManager.setConfig(keys[0], createConfig());
        assertNotNull(configManager.getConfig(keys[0]));

        configManager.setConfig(keys[1], createConfig());
        assertNotNull(configManager.getConfig(keys[1]));

        configManager.setConfig(keys[2], createConfig());
        assertNotNull(configManager.getConfig(keys[2]));

        configManager.setConfig(keys[3], createConfig());
        assertNotNull(configManager.getConfig(keys[3]));
    }

    @Test
    public void testRemoveConfigAscending() {

        final StatsKey[] keys = createKeyHierarchy();

        final StatsConfig config0 = createConfig();
        final StatsConfig config1 = createConfig();
        final StatsConfig config2 = createConfig();
        final StatsConfig config3 = createConfig();

        mockery.checking(new Expectations() {{
            ignoring(mockEventManager).fireEvent(with(EventType.CONFIG_CREATED),
                                                 with(any(StatsKey.class)),
                                                 with(aNonNull(StatsConfig.class)));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_DESTROYED),
                                            with(keys[0]),
                                            with(config0));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_DESTROYED),
                                            with(keys[1]),
                                            with(config1));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_DESTROYED),
                                            with(keys[2]),
                                            with(config2));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_DESTROYED),
                                            with(keys[3]),
                                            with(config3));
        }});

        configManager.setConfig(keys[0], config0);
        configManager.setConfig(keys[1], config1);
        configManager.setConfig(keys[2], config2);
        configManager.setConfig(keys[3], config3);

        assertSame(config0, configManager.removeConfig(keys[0]));
        assertNull(configManager.getConfig(keys[0]));
        assertNull(configManager.getConfig(keys[1]));
        assertNull(configManager.getConfig(keys[2]));
        assertNull(configManager.getConfig(keys[3]));
        assertNull(configManager.removeConfig(keys[0]));
        assertNull(configManager.removeConfig(keys[1]));
        assertNull(configManager.removeConfig(keys[2]));
        assertNull(configManager.removeConfig(keys[3]));
    }

    @Test
    public void testRemoveConfigDescending() {

        final StatsKey[] keys = createKeyHierarchy();

        final StatsConfig config0 = createConfig();
        final StatsConfig config1 = createConfig();
        final StatsConfig config2 = createConfig();
        final StatsConfig config3 = createConfig();

        mockery.checking(new Expectations() {{
            ignoring(mockEventManager).fireEvent(with(EventType.CONFIG_CREATED),
                                                 with(any(StatsKey.class)),
                                                 with(aNonNull(StatsConfig.class)));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_DESTROYED),
                                            with(keys[3]),
                                            with(config3));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_DESTROYED),
                                            with(keys[2]),
                                            with(config2));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_DESTROYED),
                                            with(keys[1]),
                                            with(config1));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_DESTROYED),
                                            with(keys[0]),
                                            with(config0));
        }});

        configManager.setConfig(keys[0], config0);
        configManager.setConfig(keys[1], config1);
        configManager.setConfig(keys[2], config2);
        configManager.setConfig(keys[3], config3);

        assertSame(config3, configManager.removeConfig(keys[3]));
        assertNull(configManager.getConfig(keys[3]));
        assertNotNull(configManager.getConfig(keys[2]));
        assertNotNull(configManager.getConfig(keys[1]));
        assertNotNull(configManager.getConfig(keys[0]));
        assertNull(configManager.removeConfig(keys[3]));

        assertSame(config2, configManager.removeConfig(keys[2]));
        assertNull(configManager.getConfig(keys[3]));
        assertNull(configManager.getConfig(keys[2]));
        assertNotNull(configManager.getConfig(keys[1]));
        assertNotNull(configManager.getConfig(keys[0]));
        assertNull(configManager.removeConfig(keys[2]));

        assertSame(config1, configManager.removeConfig(keys[1]));
        assertNull(configManager.getConfig(keys[3]));
        assertNull(configManager.getConfig(keys[2]));
        assertNull(configManager.getConfig(keys[1]));
        assertNotNull(configManager.getConfig(keys[0]));
        assertNull(configManager.removeConfig(keys[1]));

        assertSame(config0, configManager.removeConfig(keys[0]));
        assertNull(configManager.getConfig(keys[3]));
        assertNull(configManager.getConfig(keys[2]));
        assertNull(configManager.getConfig(keys[1]));
        assertNull(configManager.getConfig(keys[0]));
        assertNull(configManager.removeConfig(keys[0]));
    }

    @Test
    public void testClearConfigs() {

        final StatsKey[] keys = createKeyHierarchy();

        final StatsConfig config0 = createConfig();
        final StatsConfig config1 = createConfig();
        final StatsConfig config2 = createConfig();
        final StatsConfig config3 = createConfig();

        mockery.checking(new Expectations() {{
            ignoring(mockEventManager).fireEvent(with(EventType.CONFIG_CREATED),
                                                 with(any(StatsKey.class)),
                                                 with(aNonNull(StatsConfig.class)));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_DESTROYED),
                                            with(keys[0]),
                                            with(config0));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_DESTROYED),
                                            with(keys[1]),
                                            with(config1));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_DESTROYED),
                                            with(keys[2]),
                                            with(config2));
            one(mockEventManager).fireEvent(with(EventType.CONFIG_DESTROYED),
                                            with(keys[3]),
                                            with(config3));
        }});

        configManager.setConfig(keys[0], config0);
        configManager.setConfig(keys[1], config1);
        configManager.setConfig(keys[2], config2);
        configManager.setConfig(keys[3], config3);

        configManager.clearConfigs();

        assertNull(configManager.getConfig(keys[3]));
        assertNull(configManager.getConfig(keys[2]));
        assertNull(configManager.getConfig(keys[1]));
        assertNull(configManager.getConfig(keys[0]));
    }

}


text:
ImageOptim Kornela Lesińskiego i współpra-cowników to nakładka na następujące programy:

OptiPNG Cosmina Truty,

PNGCrush Glenna Randers-Pehrsona,

Zopfli Jyrki Alakuijaly i Lode Vandevenne,

AdvPNG Andrei Mazzoleni i Filipe Estimy,

Jpegoptim Timo Kokkonena,

Gifsicle Eddiego Kohlera,

oraz PNGOUT Kena Silvermana.

ImageOptim może być modyfikowany i rozpowszechniany na zasadach
GNU General Public License wersji 2 lub nowszej.
PNGOUT nie jest objęty GPL i został dołączony za pozwoleniem Ardfry Imaging, LLC.

redpajama_set_name: RedPajamaGithub


text:
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2020 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Markus Pfeiffer
////////////////////////////////////////////////////////////////////////////////

#include "gtest/gtest.h"

#include "QueryHelper.h"

#include "Aql/AqlItemBlockSerializationFormat.h"
#include "Aql/Ast.h"
#include "Aql/ExecutionPlan.h"
#include "Aql/Query.h"
#include "Aql/ExecutionEngine.h"
#include "Aql/ExecutionBlock.h"
#include "Aql/SubqueryEndExecutionNode.h"
#include "Aql/SubqueryStartExecutionNode.h"
#include "Aql/WalkerWorker.h"
#include "Logger/LogMacros.h"
#include "RestServer/QueryRegistryFeature.h"
#include "Transaction/Methods.h"
#include "Transaction/StandaloneContext.h"
#include "VocBase/LogicalCollection.h"
#include "VocBase/ManagedDocumentResult.h"

#include "velocypack/Builder.h"
#include "velocypack/Collection.h"
#include "velocypack/Slice.h"
#include "velocypack/StringRef.h"
#include "velocypack/velocypack-aliases.h"

#include "../IResearch/IResearchQueryCommon.h"
#include "../Mocks/Servers.h"

using namespace arangodb::aql;
using namespace arangodb::containers;

namespace {
struct Comparator final : public WalkerWorker<ExecutionNode, WalkerUniqueness::NonUnique> {
  Comparator(Comparator const&) = delete;
  Comparator& operator=(Comparator const&) = delete;

  Comparator(ExecutionPlan* other, bool expectNormalSubqueries)
      : _other(other), _expectNormalSubqueries(expectNormalSubqueries) {}

  static bool isSubqueryRelated(ExecutionNode* en) {
    return en->getType() == ExecutionNode::SUBQUERY ||
           en->getType() == ExecutionNode::SUBQUERY_START ||
           en->getType() == ExecutionNode::SUBQUERY_END ||
           en->getType() == ExecutionNode::SINGLETON;
  }

  bool before(ExecutionNode* en) override final {
    std::set<ExecutionNodeId> depids, otherdepids;

    if (!isSubqueryRelated(en)) {
      try {
        auto otherNode = _other->getNodeById(en->id());
        auto otherDeps = otherNode->getDependencies();

        for (auto d : otherDeps) {
          if (!isSubqueryRelated(d)) {
            otherdepids.insert(d->id());
          }
        }

        for (auto d : en->getDependencies()) {
          if (!isSubqueryRelated(d)) {
            depids.insert(d->id());
          }
        }

        EXPECT_EQ(depids, otherdepids);
      } catch (...) {
        EXPECT_TRUE(false) << "expected node with id " << en->id().id() << " of type "
                           << en->getTypeString() << " to be present in optimized plan";
      }
    }
    return false;
  }

  void after(ExecutionNode* en) override final {}

  bool enterSubquery(ExecutionNode*, ExecutionNode* sub) override final {
    EXPECT_TRUE(_expectNormalSubqueries)
        << "Optimized plan must not contain SUBQUERY nodes";
    return false;
  }

 private:
  ExecutionPlan* _other{};
  bool _expectNormalSubqueries{};
};

}  // namespace

namespace arangodb {
namespace tests {
namespace aql {

class SpliceSubqueryNodeOptimizerRuleTest : public ::testing::Test {
 protected:
  mocks::MockAqlServer server;
  QueryRegistry* queryRegistry{QueryRegistryFeature::registry()};

  std::shared_ptr<VPackBuilder> ruleOptions(char const* additionalOptionsString) const {
    return VPackParser::fromJson(additionalOptionsString);
  }

  void verifySubquerySplicing(std::string const& querystring,
                              size_t const expectedNumberOfSplicedSubqueries,
                              char const* bindParameters = "{}",
                              char const* additionalOptions = "{}") {
    auto const expectedNumberOfSubqueries = expectedNumberOfSplicedSubqueries;
    ASSERT_NE(queryRegistry, nullptr) << "query string: " << querystring;
    ASSERT_EQ(queryRegistry->numberRegisteredQueries(), 0) << "query string: " << querystring;

    auto ctx = std::make_shared<arangodb::transaction::StandaloneContext>(server.getSystemDatabase());
    auto const bindParamVpack = VPackParser::fromJson(bindParameters);
    auto splicedQuery = arangodb::aql::Query::create(ctx, arangodb::aql::QueryString(querystring), bindParamVpack,
                                                     arangodb::aql::QueryOptions(ruleOptions(additionalOptions)->slice()));
    splicedQuery->prepareQuery(SerializationFormat::SHADOWROWS);
    ASSERT_EQ(queryRegistry->numberRegisteredQueries(), 0) << "query string: " << querystring;

    auto splicedPlan = const_cast<arangodb::aql::ExecutionPlan*>(splicedQuery->plan());
    ASSERT_NE(splicedPlan, nullptr) << "query string: " << querystring;

    SmallVector<ExecutionNode*>::allocator_type::arena_type a;
    SmallVector<ExecutionNode*> splicedSubqueryNodes{a};
    SmallVector<ExecutionNode*> splicedSubqueryStartNodes{a};
    SmallVector<ExecutionNode*> splicedSubqueryEndNodes{a};
    SmallVector<ExecutionNode*> splicedSubquerySingletonNodes{a};
    splicedPlan->findNodesOfType(splicedSubqueryNodes, ExecutionNode::SUBQUERY, true);
    splicedPlan->findNodesOfType(splicedSubqueryStartNodes,
                                 ExecutionNode::SUBQUERY_START, true);
    splicedPlan->findNodesOfType(splicedSubqueryEndNodes, ExecutionNode::SUBQUERY_END, true);

    splicedPlan->findNodesOfType(splicedSubquerySingletonNodes,
                                 ExecutionNode::SINGLETON, true);

    EXPECT_EQ(expectedNumberOfSplicedSubqueries, splicedSubqueryStartNodes.size())
        << "query string: " << querystring;
    EXPECT_EQ(expectedNumberOfSplicedSubqueries, splicedSubqueryEndNodes.size())
        << "query string: " << querystring;

    EXPECT_EQ(splicedSubquerySingletonNodes.size(), 1)
        << "query string: " << querystring;

    // Make sure no nodes got lost (currently does not check SubqueryNodes,
    // SubqueryStartNode, SubqueryEndNode correctness)
    Comparator compare(splicedPlan, expectedNumberOfSubqueries > 0);
    splicedPlan->root()->walk(compare);
  }

  void verifyQueryResult(std::string const& query, VPackSlice const expected,
                         char const* bindParameters = "{}",
                         char const* additionalOptions = "{}") {
    auto const bindParamVPack = VPackParser::fromJson(bindParameters);
    SCOPED_TRACE("Query: " + query);

    {
      auto queryResult =
          arangodb::tests::executeQuery(server.getSystemDatabase(), query, bindParamVPack,
                                        ruleOptions(additionalOptions)->toJson());
      SCOPED_TRACE("rule was enabled");
      AssertQueryResultToSlice(queryResult, expected);
    }
  }

 public:
  SpliceSubqueryNodeOptimizerRuleTest() {}

};  // namespace aql

TEST_F(SpliceSubqueryNodeOptimizerRuleTest, splice_subquery_no_subquery_plan) {
  auto query = "RETURN 15";
  verifySubquerySplicing(query, 0);

  auto expected = arangodb::velocypack::Parser::fromJson(R"([15])");
  verifyQueryResult(query, expected->slice());
}

TEST_F(SpliceSubqueryNodeOptimizerRuleTest, splice_subquery_single_input) {
  auto query = R"aql(FOR d IN 1..1
                      LET first =
                        (RETURN 1)
                      RETURN first)aql";
  verifySubquerySplicing(query, 1);

  auto expected = arangodb::velocypack::Parser::fromJson(R"([[1]])");
  verifyQueryResult(query, expected->slice());
}

TEST_F(SpliceSubqueryNodeOptimizerRuleTest, splice_subquery_plan) {
  auto query = R"aql(FOR d IN 1..2
                      LET first =
                        (FOR e IN 1..2 FILTER d == e RETURN e)
                      RETURN first)aql";
  verifySubquerySplicing(query, 1);

  auto expected = arangodb::velocypack::Parser::fromJson(R"([[1],[2]])");
  verifyQueryResult(query, expected->slice());
}

TEST_F(SpliceSubqueryNodeOptimizerRuleTest, splice_subquery_in_subquery_plan) {
  auto query = R"aql(FOR d IN 1..2
                        LET first = (FOR e IN 1..2
                                        LET second = (FOR f IN 1..2 RETURN f)
                                        FILTER d == e RETURN [e, second])
                         RETURN first)aql";
  verifySubquerySplicing(query, 2);

  auto expected = arangodb::velocypack::Parser::fromJson(R"([
    [[1, [1,2]]],
    [[2, [1,2]]]
  ])");
  verifyQueryResult(query, expected->slice());
}

TEST_F(SpliceSubqueryNodeOptimizerRuleTest, splice_subquery_after_subquery_plan) {
  auto query = R"aql(FOR d IN 1..2
                        LET first = (FOR e IN 1..2 FILTER d == e RETURN e)
                        LET second = (FOR e IN 1..2 FILTER d != e RETURN e)
                        RETURN [first, second])aql";
  verifySubquerySplicing(query, 2);

  auto expected = arangodb::velocypack::Parser::fromJson(R"([[[1],[2]],[[2],[1]]])");
  verifyQueryResult(query, expected->slice());
}

TEST_F(SpliceSubqueryNodeOptimizerRuleTest, splice_subquery_with_sort) {
  auto query = R"aql(
    FOR i IN 1..2
      LET sorted = (
        FOR k IN [1,5,3,2,4,6]
          LET h = k * i
          SORT h DESC
        RETURN h
      )
      RETURN sorted)aql";
  verifySubquerySplicing(query, 1);

  auto expected = arangodb::velocypack::Parser::fromJson(R"([[6,5,4,3,2,1], [12,10,8,6,4,2]])");
  verifyQueryResult(query, expected->slice());
}

TEST_F(SpliceSubqueryNodeOptimizerRuleTest, splice_subquery_with_skip__inner_limit_offset) {
  auto const queryString = R"aql(FOR i IN 0..2
    LET a = (FOR j IN 0..2 LIMIT 1, 1 RETURN 3*i + j)
    RETURN FIRST(a))aql";
  auto const expectedString = R"res([1, 4, 7])res";

  verifySubquerySplicing(queryString, 1);
  auto expected = arangodb::velocypack::Parser::fromJson(expectedString);
  verifyQueryResult(queryString, expected->slice());
}

TEST_F(SpliceSubqueryNodeOptimizerRuleTest, splice_subquery_with_skip__outer_limit_offset) {
  auto const queryString = R"aql(FOR i IN 0..2
    LET a = (FOR j IN 0..2 RETURN 3*i + j)
    LIMIT 1, 1
    RETURN FIRST(a))aql";
  auto const expectedString = R"res([3])res";

  verifySubquerySplicing(queryString, 1);
  auto expected = arangodb::velocypack::Parser::fromJson(expectedString);
  verifyQueryResult(queryString, expected->slice());
}

TEST_F(SpliceSubqueryNodeOptimizerRuleTest, splice_subquery_with_skip__inner_collect_count) {
  auto const queryString = R"aql(FOR i IN 0..2
    LET a = (FOR j IN 0..i COLLECT WITH COUNT INTO n RETURN n)
    RETURN FIRST(a))aql";
  auto const expectedString = R"res([1, 2, 3])res";

  verifySubquerySplicing(queryString, 1);
  auto expected = arangodb::velocypack::Parser::fromJson(expectedString);
  verifyQueryResult(queryString, expected->slice());
}

TEST_F(SpliceSubqueryNodeOptimizerRuleTest, splice_subquery_with_skip__outer_collect_count) {
  // the RAND() is there to avoid the subquery being removed
  auto const queryString = R"aql(FOR i IN 0..2
    LET a = (FOR j IN 0..FLOOR(2*RAND()) RETURN 1)
    COLLECT WITH COUNT INTO n
    RETURN n)aql";
  auto const expectedString = R"res([3])res";

  verifySubquerySplicing(queryString, 1);
  auto expected = arangodb::velocypack::Parser::fromJson(expectedString);
  verifyQueryResult(queryString, expected->slice());
}

// Must be changed as soon as the subquery implementation with shadow rows handle skipping,
// and the splice-subqueries optimizer rule is changed to allow it.
TEST_F(SpliceSubqueryNodeOptimizerRuleTest, splice_subquery_with_skip__full_count) {
  // the RAND() is there to avoid the subquery being removed
  auto const queryString = R"aql(FOR i IN 0..2
    LET a = (FOR j IN 0..FLOOR(2*RAND()) RETURN 1)
    LIMIT 1
    RETURN i)aql";
  auto const expectedString = R"res([0])res";

  verifySubquerySplicing(queryString, 1, "{}", R"opts({"fullCount": true})opts");
  auto expected = arangodb::velocypack::Parser::fromJson(expectedString);
  verifyQueryResult(queryString, expected->slice());
}

// Must be changed as soon as the subquery implementation with shadow rows handle skipping,
// and the splice-subqueries optimizer rule is changed to allow it.
TEST_F(SpliceSubqueryNodeOptimizerRuleTest, splice_nested_subquery) {
  auto const queryString = R"aql(
    FOR i IN 0..1
    LET js = ( // this subquery should be spliced
      FOR j IN 0..1 + FLOOR(RAND())
      LET ks = ( // this subquery should be spliced
        FOR k IN 0..1 + FLOOR(RAND())
        RETURN 4*i + 2*j + k
      )
      RETURN ks
    )
    RETURN js
  )aql";
  auto const expectedString = R"res([[[0, 1], [2, 3]], [[4, 5], [6, 7]]])res";

  verifySubquerySplicing(queryString, 2);
  auto expected = arangodb::velocypack::Parser::fromJson(expectedString);
  verifyQueryResult(queryString, expected->slice());
}

// Must be changed as soon as the subquery implementation with shadow rows handle skipping,
// and the splice-subqueries optimizer rule is changed to allow it.
TEST_F(SpliceSubqueryNodeOptimizerRuleTest, splice_nested_subquery_with_innermost_skip) {
  auto const queryString = R"aql(
    FOR i IN 0..1
    LET js = ( // this subquery should be spliced
      FOR j IN 0..1 + FLOOR(RAND())
      LET ks = ( // this subquery should be spliced
        FOR k IN 0..2 + FLOOR(RAND())
        LIMIT 1, 2
        RETURN 6*i + 3*j + k
      )
      RETURN ks
    )
    RETURN js
  )aql";
  auto const expectedString = R"res([[[1, 2], [4, 5]], [[7, 8], [10, 11]]])res";

  verifySubquerySplicing(queryString, 2);
  auto expected = arangodb::velocypack::Parser::fromJson(expectedString);
  verifyQueryResult(queryString, expected->slice());
}

// Must be changed as soon as the subquery implementation with shadow rows
// handle skipping, and the splice-subqueries optimizer rule is changed to allow
// it. This is a test for a specific problem where constant subqueries did not
// work inside spliced subqueries correctly.
TEST_F(SpliceSubqueryNodeOptimizerRuleTest, splice_nested_subquery_with_innermost_constant_skip) {
  auto const queryString = R"aql(
    FOR a IN 1..2
      LET b = (RETURN (FOR c IN 2..4 LIMIT 1, null RETURN c) )
    RETURN {a, b}
  )aql";
  auto const expectedString = R"res([{"a": 1, "b": [[3, 4]]}, {"a": 2, "b": [[3, 4]]}])res";

  verifySubquerySplicing(queryString, 2);
  auto expected = arangodb::velocypack::Parser::fromJson(expectedString);
  verifyQueryResult(queryString, expected->slice());
}

// Must be changed as soon as the subquery implementation with shadow rows handle skipping,
// and the splice-subqueries optimizer rule is changed to allow it.
TEST_F(SpliceSubqueryNodeOptimizerRuleTest, splice_nested_subquery_with_outermost_skip) {
  auto const queryString = R"aql(
    FOR i IN 0..2
    LET js = ( // this subquery should be spliced
      FOR j IN 0..1 + FLOOR(RAND())
      LET ks = ( // this subquery should be spliced
        FOR k IN 0..1 + FLOOR(RAND())
        RETURN 4*i + 2*j + k
      )
      RETURN ks
    )
    LIMIT 1, 2
    RETURN js
  )aql";
  auto const expectedString = R"res([[[4, 5], [6, 7]], [[8, 9], [10, 11]]])res";

  verifySubquerySplicing(queryString, 2);
  auto expected = arangodb::velocypack::Parser::fromJson(expectedString);
  verifyQueryResult(queryString, expected->slice());
}

// Must be changed as soon as the subquery implementation with shadow rows handle skipping,
// and the splice-subqueries optimizer rule is changed to allow it.
TEST_F(SpliceSubqueryNodeOptimizerRuleTest, splice_subquery_with_limit_and_no_offset) {
  auto query = R"aql(
    FOR i IN 2..4
      LET a = (FOR j IN [i, i+10, i+20] LIMIT 0, 1 RETURN j)
      RETURN FIRST(a))aql";
  verifySubquerySplicing(query, 1);

  auto expected = arangodb::velocypack::Parser::fromJson(R"([2, 3, 4])");
  verifyQueryResult(query, expected->slice());
}

// Regression test for https://github.com/arangodb/arangodb/issues/10852
TEST_F(SpliceSubqueryNodeOptimizerRuleTest, splice_nested_empty_subqueries) {
  auto const queryString = R"aql(
    LET results = (
        FOR doc IN []
            LET docs = (
                FOR doc2 in []
                    RETURN doc2
            )
            RETURN [docs]
    )

    RETURN [results]
  )aql";
  auto const expectedString = R"res([[[]]])res";
  verifySubquerySplicing(queryString, 2);
  auto expected = arangodb::velocypack::Parser::fromJson(expectedString);
  verifyQueryResult(queryString, expected->slice());
}

// Regression test for https://github.com/arangodb/arangodb/issues/10852
TEST_F(SpliceSubqueryNodeOptimizerRuleTest, splice_subquery_with_upsert) {
  TRI_vocbase_t& vocbase{server.getSystemDatabase()};
  auto const info = VPackParser::fromJson(R"({"name":"UnitTestCollection"})");
  auto const collection = vocbase.createCollection(info->slice());
  auto const queryString = R"aql(
    LET new_id = (
        UPSERT { _key: @key }
        INSERT { _key: @key }
        UPDATE { _key: @key }
        IN UnitTestCollection
        RETURN NEW._id
    )
    RETURN new_id
  )aql";

  auto const bindString = R"bind({"key": "myKey"})bind";
  auto const expectedString = R"res([["UnitTestCollection/myKey"]])res";

  verifySubquerySplicing(queryString, 2, bindString);
  auto expected = arangodb::velocypack::Parser::fromJson(expectedString);
  verifyQueryResult(queryString, expected->slice(), bindString);

  auto const noCollections = std::vector<std::string>{};
  auto const readCollection = std::vector<std::string>{"UnitTestCollection"};
  transaction::Options opts;
  auto ctx = transaction::StandaloneContext::Create(server.getSystemDatabase());
  auto trx = std::make_unique<arangodb::transaction::Methods>(ctx, readCollection, noCollections,
                                                              noCollections, opts);
  ASSERT_EQ(1, collection->numberDocuments(trx.get(), transaction::CountType::Normal));
  bool called = false;
  auto result = collection->getPhysical()->read(trx.get(), arangodb::velocypack::StringRef{"myKey"}, [&](LocalDocumentId const&, VPackSlice document) {
    called = true;
    EXPECT_TRUE(document.isObject());
    EXPECT_TRUE(document.get("_key").isString());
    EXPECT_EQ(std::string{"myKey"}, document.get("_key").copyString());
    return true;
  }, arangodb::ReadOwnWrites::no);
  ASSERT_TRUE(called);
  ASSERT_TRUE(result.ok());
}

// Regression test for https://github.com/arangodb/arangodb/issues/10896
TEST_F(SpliceSubqueryNodeOptimizerRuleTest, splice_subquery_before_collect) {
  auto const queryString = R"aql(
    LET tokens = (
      FOR word IN TOKENS("Some Text", "text_en")
        FILTER word IN TOKENS("Some Other Thing", "text_en")
        RETURN word
    )
    COLLECT token = tokens INTO bucket
    RETURN bucket[0]
  )aql";

  auto const expectedString = R"res([ {"tokens": ["some"]} ])res";

  verifySubquerySplicing(queryString, 1);
  auto expected = arangodb::velocypack::Parser::fromJson(expectedString);
  verifyQueryResult(queryString, expected->slice());
}

/*
 * `COLLECT ... INTO group` should not collect any variables declared outside
 * its containing subquery, especially not from subqueries before it.
 */
TEST_F(SpliceSubqueryNodeOptimizerRuleTest, splice_subquery_with_collect_after_spliced_subquery) {
  auto const queryString = R"aql(
    FOR x IN 0..2
      LET is = (FOR i IN 0..2 RETURN i + 3*x)
      LET ys = (
        FOR y IN 0..x
          COLLECT p = 1 INTO group
          RETURN {x, is, group}
      )
      RETURN {ys}
  )aql";

  auto const expectedString = R"res([
    {"ys": [ {"x": 0, "is": [0, 1, 2], "group": [{"y": 0}] } ] },
    {"ys": [ {"x": 1, "is": [3, 4, 5], "group": [{"y": 0}, {"y": 1}] } ] },
    {"ys": [ {"x": 2, "is": [6, 7, 8], "group": [{"y": 0}, {"y": 1}, {"y": 2}] } ] }
  ])res";

  verifySubquerySplicing(queryString, 2);
  auto expected = arangodb::velocypack::Parser::fromJson(expectedString);
  verifyQueryResult(queryString, expected->slice());
}

/*
 * `COLLECT ... INTO group` should not collect any variables declared outside
 * its containing subquery, especially not from subqueries before it.
 */
TEST_F(SpliceSubqueryNodeOptimizerRuleTest,
       splice_subquery_with_collect_after_spliced_subquery_with_collect) {
  auto const queryString = R"aql(
    FOR x IN 0..2
      LET is = (
        LET f = "foo"
        FOR i IN 0..x
          COLLECT p = 1 INTO igroup
          RETURN {x, igroup}
      )
      LET ys = (
        LET b = "bar"
        FOR y IN 0..x
          COLLECT p = 1 INTO ygroup
          RETURN {x, is, ygroup}
      )
      RETURN {ys}
  )aql";

  auto const expectedString = R"res([
    {"ys": [{
          "x": 0,
          "is": [{"x": 0, "igroup": [{"i": 0}]}],
          "ygroup": [{"y": 0}]
        }]},
    {"ys": [{
          "x": 1,
          "is": [{"x": 1, "igroup": [{"i": 0}, {"i": 1}]}],
          "ygroup": [{"y": 0}, {"y": 1}]
        }]},
    {"ys": [{
          "x": 2,
          "is": [{"x": 2, "igroup": [{"i": 0}, {"i": 1}, {"i": 2}]}],
          "ygroup": [{"y": 0}, {"y": 1}, {"y": 2}]
        }]}
  ])res";

  verifySubquerySplicing(queryString, 2);
  auto expected = arangodb::velocypack::Parser::fromJson(expectedString);
  verifyQueryResult(queryString, expected->slice());
}

/*
 * Inside a subquery a relative top-level collect should behave correctly (and collect top level variables)
 */
TEST_F(SpliceSubqueryNodeOptimizerRuleTest, splice_subquery_with_relative_top_level_collect) {
  auto const queryString = R"aql(
    LET y = (
      LET x = 12
      LET y = (FOR m IN 1..3 COLLECT mm = m INTO bar RETURN mm)
      COLLECT p = 1 INTO groups
      RETURN groups
    )
    RETURN y
  )aql";

  auto const expectedString = R"res([
    [
      [
        {"x":12, "y":[1, 2, 3]}
      ]
    ]
  ])res";

  verifySubquerySplicing(queryString, 2);
  auto expected = arangodb::velocypack::Parser::fromJson(expectedString);
  verifyQueryResult(queryString, expected->slice());
}

/*
 * Subqueries at top-level should not change the behavior of top-level collect
 * (and should not captures variables within these subqueries)
 */
TEST_F(SpliceSubqueryNodeOptimizerRuleTest,
       splice_subquery_with_nested_queries_and_top_level_collect) {
  auto const queryString = R"aql(
    LET y = (
      LET z = (FOR m IN 1..3 COLLECT mm = m INTO bar RETURN mm)
      RETURN z
    )
    COLLECT yy = y INTO bar
    RETURN bar
  )aql";

  auto const expectedString = R"res([
    [{
      "y": [[1, 2, 3]]
    }]
  ])res";

  verifySubquerySplicing(queryString, 2);
  auto expected = arangodb::velocypack::Parser::fromJson(expectedString);
  verifyQueryResult(queryString, expected->slice());
}

/*
 * Subqueries at top-level should not change the behavior of top-level collect
 * (and should not captures variables within these subqueries)
 */
TEST_F(SpliceSubqueryNodeOptimizerRuleTest,
       splice_subquery_with_nested_queries_and_collect_in_nested_subquery) {
  auto const queryString = R"aql(
    LET foo = (
        LET y = ( FOR x IN 1..6 RETURN x )
        FOR z IN 0..2
            RETURN y[2*z]
    )

    LET bar = (
        LET v = 13
        LET y = (
          LET k = 12
          FOR x IN foo
            COLLECT p = 0 INTO bar
            RETURN bar
        )
        RETURN y
    )

    RETURN bar
  )aql";

  auto const expectedString = R"res([
    [[
      [
        {"x":1}, {"x":3}, {"x":5}
      ]
    ]]
  ])res";

  verifySubquerySplicing(queryString, 4);
  auto expected = arangodb::velocypack::Parser::fromJson(expectedString);
  verifyQueryResult(queryString, expected->slice());
}

/*
 * A subquery with a collect should not affect a collect outside of that subquery.
 */
TEST_F(SpliceSubqueryNodeOptimizerRuleTest, splice_subquery_with_collect_and_outside_collect) {
  auto const queryString = R"aql(
    LET k = 12
    FOR x IN 0..5
        LET y = (FOR y IN 0..x COLLECT p = y % 2 WITH COUNT INTO n RETURN n)
        COLLECT p = y[0] == y[1] INTO bar
        RETURN bar
  )aql";

  auto const expectedString = R"res([
    [
      {"x":0, "y":[1]}, {"x":2, "y":[2, 1]}, {"x":4, "y":[3, 2]}
    ],
    [
      {"x":1, "y":[1, 1]}, {"x":3, "y":[2, 2]}, {"x":5, "y":[3, 3]}
    ]
  ])res";

  verifySubquerySplicing(queryString, 1);
  auto expected = arangodb::velocypack::Parser::fromJson(expectedString);
  verifyQueryResult(queryString, expected->slice());
}

/*
 * A collect in a subquery should not collect top-level variables.
 */
TEST_F(SpliceSubqueryNodeOptimizerRuleTest, splice_subquery_with_collect_in_subquery) {
  auto const queryString = R"aql(
    LET k = 14
    LET x = (
        LET y = (FOR x IN 1..6 FILTER 1 == x % 2 RETURN 2*x)
        FOR x IN 1..3
            COLLECT p = y[x] % 4 INTO baz
            RETURN baz
    )

    RETURN x
  )aql";

  auto const expectedString = R"res([
    [
      [{"x": 3}],
      [{"x": 1}, {"x": 2}]
    ]
  ])res";

  verifySubquerySplicing(queryString, 2);
  auto expected = arangodb::velocypack::Parser::fromJson(expectedString);
  verifyQueryResult(queryString, expected->slice());
}

TEST_F(SpliceSubqueryNodeOptimizerRuleTest, splice_subquery_with_limit_and_offset) {
  auto query = R"aql(
    FOR i IN 2..4
      LET a = (FOR j IN [0, i, i+10] LIMIT 1, 1 RETURN j)
      RETURN FIRST(a))aql";
  verifySubquerySplicing(query, 1);

  auto expected = arangodb::velocypack::Parser::fromJson(R"([2, 3, 4])");
  verifyQueryResult(query, expected->slice());
}

TEST_F(SpliceSubqueryNodeOptimizerRuleTest, splice_subquery_collect_within_empty_nested_subquery) {
  auto query = R"aql(
    FOR k IN 1..2
      LET sub1 = (
        FOR x IN []
          LET sub2 = (
            COLLECT WITH COUNT INTO q
            RETURN q
          )
        RETURN sub2
      )
    RETURN [k, sub1])aql";
  verifySubquerySplicing(query, 2);

  auto expected = arangodb::velocypack::Parser::fromJson(R"([[1, []], [2, []]])");
  verifyQueryResult(query, expected->slice());
}

TEST_F(SpliceSubqueryNodeOptimizerRuleTest, splice_subquery_skip_nodes) {
  auto query = R"aql(
    FOR k IN 1..10
      LET sub1 = (
        FOR j IN 1..10
        LET sub2 = (
          FOR i IN 1..4
          LIMIT 2,10
          RETURN i
        )
        LIMIT 2,10
        RETURN [j, sub2]
      )
      LIMIT 3, 10
      RETURN [k, sub1])aql";
  verifySubquerySplicing(query, 2);

  VPackBuilder builder;
  builder.openArray();
  for (size_t k = 4; k <= 10; ++k) {
    builder.openArray();
    builder.add(VPackValue(k));
    builder.openArray();
    for (size_t j = 3; j <= 10; ++j) {
      builder.openArray();
      builder.add(VPackValue(j));
      builder.openArray();
      for (size_t i = 3; i <= 4; ++i) {
        builder.add(VPackValue(i));
      }
      builder.close();
      builder.close();
    }
    builder.close();
    builder.close();
  }
  builder.close();
  verifyQueryResult(query, builder.slice());
}

// TODO Check isInSplicedSubquery
// TODO Test cluster rules

}  // namespace aql
}  // namespace tests
}  // namespace arangodb


text:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;
using System.Windows;
using System.Windows.Shapes;
using System.Windows.Media.Imaging;

namespace DesignScriptStudio.Graph.Core
{
    enum PreviewTypes
    {
        None = 0x00,
        String = 0x01,
        Bitmap = 0x02,
        Unknown = 0x04,
        Extended = 0x10,
        Collapsed = 0x20,
    }

    class PreviewBubble : InfoBubble
    {
        internal PreviewTypes PreviewType
        {
            get { return this.previewType; }
        }

        public bool Extended
        {
            get
            {
                return this.previewType.HasFlag(PreviewTypes.Extended);
            }
        }

        #region Class Data Members

        PreviewTypes previewType = PreviewTypes.None;
        private List<string> condensedString;
        private double extendedBubbleWidth = double.MinValue;
        private double extendedBubbleHeight = double.MinValue;

        #endregion

        #region Internal Class Methods

        internal PreviewBubble(IGraphController graphController, uint nodeId)
            : base(graphController, nodeId)
        {

        }

        internal void SetUnknownPreview()
        {
            this.content = UiStrings.LoadingPreviewMessage;
            previewType = PreviewTypes.Unknown;
            previewType |= PreviewTypes.Collapsed;
            condensedString = Condense(content.ToString());
            this.extendedBubbleWidth = double.MinValue;
            this.extendedBubbleHeight = double.MinValue;
        }

        internal override void SetContent(object content)
        {
            this.content = content;
            previewType &= ~PreviewTypes.String;
            previewType &= ~PreviewTypes.Bitmap;
            previewType &= ~PreviewTypes.Unknown;
            VisualNode node = graphController.GetVisualNode(this.nodeId);

            DesignScriptStudio.Renderer.ThumbnailData thumbnailData = null;
            thumbnailData = content as DesignScriptStudio.Renderer.ThumbnailData;
            if (null != thumbnailData)
            {
                int stride = thumbnailData.width * 4;
                this.content = BitmapSource.Create(thumbnailData.width, thumbnailData.height,
                    96, 96, PixelFormats.Bgra32, null, thumbnailData.pixels, stride);

                previewType |= PreviewTypes.Bitmap;
            }
            else if (null != content as BitmapSource)
            {
                this.content = content as BitmapSource;
                previewType |= PreviewTypes.Bitmap;
            }
            else
            {
                if (content == null)
                    condensedString = null;
                else
                    condensedString = Condense(content.ToString());

                previewType |= PreviewTypes.String;
            }

            this.extendedBubbleWidth = double.MinValue;
            this.extendedBubbleHeight = double.MinValue;
            node.Dirty = true;
        }

        internal double GetExtendedBubbleWidth()
        {
            if (extendedBubbleWidth < 0)
                extendedBubbleWidth = base.rectWidth;

            return extendedBubbleWidth;
        }

        internal double GetExtendedBubbleHeight()
        {
            return extendedBubbleHeight;
        }

        internal void SetExtendedBubbleSize(double width, double height)
        {
            this.extendedBubbleWidth = width;
            this.extendedBubbleHeight = height;
        }

        internal void Extend(bool extend)
        {
            if (previewType.HasFlag(PreviewTypes.Bitmap))
                return;

            if (!extend)
            {
                if (this.previewType.HasFlag(PreviewTypes.Extended))
                {
                    this.previewType &= ~PreviewTypes.Extended;
                    this.Compose();
                }
            }
            else
            {
                if (!this.previewType.HasFlag(PreviewTypes.Extended))
                {
                    this.previewType |= PreviewTypes.Extended;
                    this.Compose();
                }
            }
        }

        internal void Collapse(bool collapse)
        {
            if (!collapse)
            {
                if (previewType.HasFlag(PreviewTypes.Collapsed))
                {
                    this.previewType &= ~PreviewTypes.Collapsed;
                    this.Compose();
                }
            }
            else
            {
                if (!previewType.HasFlag(PreviewTypes.Collapsed))
                {
                    this.previewType |= PreviewTypes.Collapsed;
                    this.Compose();
                }
            }
        }

        internal bool Hittest(Point mousePosition)
        {
            Point pt = this.anchorPoint;
            pt.Offset(this.rectWidth / 2, 0);

            if (mousePosition.X > pt.X - Configurations.HittestPixels && mousePosition.X <= pt.X)
                if (mousePosition.Y >= pt.Y && mousePosition.Y <= pt.Y + Configurations.HittestPixels + Configurations.TextVerticalOffset)
                    return true;
            return false;
        }

        internal void Compose()
        {
            GraphController controller = graphController as GraphController;
            IGraphVisualHost visualHost = controller.GetVisualHost();
            if (null == visualHost)
                return; // Running in headless mode, draw no further.

            VisualNode node = graphController.GetVisualNode(nodeId);

            DrawingVisual bubbleVisual = visualHost.GetDrawingVisualForBubble(this.bubbleId);
            DrawingContext drawingContext = bubbleVisual.RenderOpen();

            if (content == null)
            {
                drawingContext.Close();
                return;
            }
            anchorPoint.X = node.GetBubbleXPosition();
            anchorPoint.Y = node.Height + Configurations.InfoBubbleTopMargin;
            anchorPoint = new Point((int)anchorPoint.X, (int)anchorPoint.Y);
            arrowLeft = new Point((int)(anchorPoint.X - Configurations.InfoBubbleArrowWidthHalf), (int)(anchorPoint.Y + Configurations.InfoBubbleArrowHeight));
            arrowRight = new Point((int)(anchorPoint.X + Configurations.InfoBubbleArrowWidthHalf), (int)(anchorPoint.Y + Configurations.InfoBubbleArrowHeight));

            if (this.previewType.HasFlag(PreviewTypes.Collapsed))
            {
                arrowLeft.Y = anchorPoint.Y;
                anchorPoint.Y = arrowRight.Y;
                arrowRight.Y = arrowLeft.Y;
            }
            else
            {
                arrowLeft.Offset(-1, 2);
                arrowRight.Offset(1, 2);
            }

            if (this.previewType.HasFlag(PreviewTypes.String)
                || this.previewType.HasFlag(PreviewTypes.Unknown))
                this.ComposeValue(drawingContext);
            else if (this.previewType.HasFlag(PreviewTypes.Bitmap))
                this.ComposeGeo(drawingContext);
            drawingContext.Close();

            TranslateTransform transform = bubbleVisual.Transform as TranslateTransform;
            transform.X = node.X;
            transform.Y = node.Y;
        }

        #endregion

        #region Private Class Methods

        private void ComposeValue(DrawingContext drawingContext)
        {
            Brush backgroundColor = null;
            Pen borderPen = null;
            if (!previewType.HasFlag(PreviewTypes.Extended))  // only need to condensed bubble
            {
                string text = Configurations.PreviewBubbleTextDefault;
                string text2 = "";
                if (condensedString != null && condensedString.Count > 0)
                {
                    text = condensedString[0];
                    if (condensedString.Count() > 1)
                        text2 = condensedString[1];
                }

                FormattedText newText;
                FormattedText newText2;
                double textLength;

                SolidColorBrush textColor;
                int textHorizontalMargin = Configurations.InfoBubbleMargin;
                int textVerticalMargin = Configurations.InfoBubbleMargin;

                textColor = Configurations.PreviewBubbleCondensedTextColor;

                newText = new FormattedText(text,
                                         Configurations.culture,
                                         FlowDirection.LeftToRight,
                                         Configurations.TypeFace,
                                         Configurations.InfoBubbleText,
                                         textColor);
                newText2 = new FormattedText(text2,
                                         Configurations.culture,
                                         FlowDirection.LeftToRight,
                                         Configurations.TypeFace,
                                         Configurations.InfoBubbleText,
                                         textColor);

                if (this.content == null)
                    newText.SetFontStyle(FontStyles.Italic);

                newText.LineHeight = Configurations.InfoBubbleText;
                textLength = Math.Max(newText.WidthIncludingTrailingWhitespace, newText2.WidthIncludingTrailingWhitespace);

                rectWidth = (int)(textLength + 2 * textHorizontalMargin);
                if (rectWidth < Configurations.InfoBubbleMinWidth)
                {
                    rectWidth = Configurations.InfoBubbleMinWidth;
                }
                if (this.previewType.HasFlag(PreviewTypes.Extended))
                {
                    rectWidth += Configurations.PreviewBubbleExtendedScrollBarWidth;
                    if (rectWidth > Configurations.InfoBubbleMaxWidth)
                        rectWidth = Configurations.InfoBubbleMaxWidth;
                }

                rectHeight = (int)(textVerticalMargin * 2 + newText.Height);
                if (text2 != "")
                    rectHeight += Configurations.InfoBubbleText + textVerticalMargin;
                if (rectHeight > Configurations.InfoBubbleMaxHeight)
                    rectHeight = Configurations.InfoBubbleMaxHeight;

                backgroundColor = Configurations.PreviewBubbleCondensedBackground;
                borderPen = Configurations.PreviewBubbleCondensedBorderPen;

                rectPoint = new Point((int)(anchorPoint.X - rectWidth / 2) + 0.5, (int)(anchorPoint.Y + Configurations.InfoBubbleArrowHeight) + 0.5);

                //Draw Bubble
                base.DrawBubble(drawingContext, backgroundColor, borderPen, !this.previewType.HasFlag(PreviewTypes.Collapsed));

                if (!this.previewType.HasFlag(PreviewTypes.Collapsed))
                {
                    //Draw text only in the condensed mode
                    double newTextWidth = newText.WidthIncludingTrailingWhitespace;
                    double newText2Width = newText2.WidthIncludingTrailingWhitespace;

                    if (text2 == "")
                    {
                        drawingContext.DrawText(newText, new Point(anchorPoint.X - newTextWidth / 2, rectPoint.Y + textVerticalMargin));
                    }
                    else
                    {
                        drawingContext.DrawText(newText, new Point(rectPoint.X + Configurations.InfoBubbleMargin, rectPoint.Y + textVerticalMargin));
                        drawingContext.DrawText(newText2, new Point(rectPoint.X + Configurations.InfoBubbleMargin, rectPoint.Y + textVerticalMargin + newText.Height));
                    }

                    //Draw Context Menu
                    Point p = new Point(rectPoint.X + rectWidth, rectPoint.Y);
                    p.Offset(0, Configurations.ContextMenuMargin);
                    DrawingUtilities.DrawDots(drawingContext, DotTypes.Top | DotTypes.TopRight | DotTypes.MiddleRight, p, Core.AnchorPoint.TopRight, false);
                }
            }
        }

        private void ComposeGeo(DrawingContext drawingContext)
        {
            rectWidth = Configurations.PreviewBubbleGeoSize;
            rectHeight = Configurations.PreviewBubbleGeoSize;
            BitmapSource image = this.content as BitmapSource;
            if (null != image)
            {
                rectWidth = image.PixelWidth;
                rectHeight = image.PixelHeight;
            }

            rectPoint = new Point((int)(anchorPoint.X - rectWidth / 2),
                (int)(anchorPoint.Y + Configurations.InfoBubbleArrowHeight));

            //Draw Bubble
            Brush backgroundColor;
            Pen borderPen;
            if (this.previewType.HasFlag(PreviewTypes.Collapsed))
            {
                backgroundColor = Configurations.PreviewBubbleMinGeoBackground;
                borderPen = borderPen = Configurations.PreviewBubbleMinGeoBorderPen;
            }
            else
            {
                backgroundColor = Configurations.PreviewBubbleGeoBackground;
                borderPen = borderPen = Configurations.PreviewBubbleGeoBorderPen;
            }
            base.DrawBubble(drawingContext, backgroundColor, borderPen, !this.previewType.HasFlag(PreviewTypes.Collapsed));

            if (!this.previewType.HasFlag(PreviewTypes.Collapsed))
            {
                Rect newRect = new Rect(rectPoint, new Size(rectWidth, rectHeight));
                // @TODO(Ben): Remove "ResourceNames.RadialBlueImagePath" if needed.
                // string imagePath = ResourceNames.RadialBlueImagePath;
                drawingContext.DrawImage(image, newRect);

                //Draw Context Menu
                Point p = new Point(rectPoint.X + rectWidth, rectPoint.Y);
                p.Offset(0, Configurations.ContextMenuMargin);
                DrawingUtilities.DrawDots(drawingContext, DotTypes.Top | DotTypes.TopRight | DotTypes.MiddleRight, p, Core.AnchorPoint.TopRight, false);
            }
        }

        private List<string> Condense(string extendedString)
        {
            List<string> condensedStrings = new List<string>();

            string temp = CondenseNumbers(extendedString);

            if (extendedString[0] == '{')  // Collection
            {
                if (temp.Count() < 100)
                    condensedStrings.Add(temp);
                else
                    condensedStrings = CondenseString(temp);
            }
            else
            {
                condensedStrings = CondenseString(temp);
            }

            return condensedStrings;
        }

        private List<string> CondenseString(string extendedString)
        {
            List<string> condensedStrings = new List<string>();

            if (extendedString.Count() < 50)
                condensedStrings.Add(extendedString);
            else if (extendedString.Count() < 100)
            {
                int half = extendedString.Count() / 2;
                condensedStrings.Add(extendedString.Substring(0, half));
                condensedStrings.Add(extendedString.Substring(half));
            }
            else
            {
                condensedStrings.Add(extendedString.Substring(0, 47) + "...");
                condensedStrings.Add(extendedString.Substring(extendedString.Count() - 1 - 50));
            }

            return condensedStrings;
        }

        private string CondenseNumbers(string extendedString)
        {
            string sourceString = extendedString;
            string targetString = "";

            string[] split = extendedString.Split(new Char[] { ' ', ',', '{', '}', '(', ')' });

            for (int i = 0; i < split.Count(); i++)
            {
                double n;
                if (string.IsNullOrEmpty(split[i]))
                    continue;

                string temp;
                int index;

                if (double.TryParse(split[i], out n))
                    temp = CondenseDigit(split[i]);
                else
                    temp = split[i];

                index = sourceString.IndexOf(split[i]);
                targetString += sourceString.Substring(0, index);
                targetString += temp;
                sourceString = sourceString.Substring(index + split[i].Length, sourceString.Length - split[i].Length - index);
            }
            targetString += sourceString;

            return targetString;
        }

        private string CondenseDigit(string number)
        {
            string condensedNumber = number;
            if (number.Contains("."))
            {
                condensedNumber = condensedNumber.Substring(0, condensedNumber.Length - 3);

                while (condensedNumber.Last() == '0')
                    condensedNumber = condensedNumber.Substring(0, condensedNumber.Length - 1);
                if (condensedNumber.Last() == '.')
                    condensedNumber = condensedNumber.Substring(0, condensedNumber.Length - 1);
            }
            return condensedNumber;
        }

        #endregion
    }
}


text:
require 'spec_helper'

RSpec.describe Namespace::AggregationSchedule, :clean_gitlab_redis_shared_state, type: :model do
  include ExclusiveLeaseHelpers

  it { is_expected.to belong_to :namespace }

  describe '#schedule_root_storage_statistics' do
    let(:namespace) { create(:namespace) }
    let(:aggregation_schedule) { namespace.build_aggregation_schedule }
    let(:lease_key) { "namespace:namespaces_root_statistics:#{namespace.id}" }

    context "when we can't obtain the lease" do
      it 'does not schedule the workers' do
        stub_exclusive_lease_taken(lease_key, timeout: described_class::DEFAULT_LEASE_TIMEOUT)

        expect(Namespaces::RootStatisticsWorker)
          .not_to receive(:perform_async)

        expect(Namespaces::RootStatisticsWorker)
          .not_to receive(:perform_in)

        aggregation_schedule.save!
      end
    end

    context 'when we can obtain the lease' do
      it 'schedules a root storage statistics after create' do
        stub_exclusive_lease(lease_key, timeout: described_class::DEFAULT_LEASE_TIMEOUT)

        expect(Namespaces::RootStatisticsWorker)
          .to receive(:perform_async).once

        expect(Namespaces::RootStatisticsWorker)
          .to receive(:perform_in).once
          .with(described_class::DEFAULT_LEASE_TIMEOUT, aggregation_schedule.namespace_id)

        aggregation_schedule.save!
      end

      it 'does not release the lease' do
        stub_exclusive_lease(lease_key, timeout: described_class::DEFAULT_LEASE_TIMEOUT)

        aggregation_schedule.save!

        exclusive_lease = aggregation_schedule.exclusive_lease
        expect(exclusive_lease.exists?).to be_truthy
      end

      it 'only executes the workers once' do
        # Avoid automatic deletion of Namespace::AggregationSchedule
        # for testing purposes.
        expect(Namespaces::RootStatisticsWorker)
          .to receive(:perform_async).once
          .and_return(nil)

        expect(Namespaces::RootStatisticsWorker)
          .to receive(:perform_in).once
          .with(described_class::DEFAULT_LEASE_TIMEOUT, aggregation_schedule.namespace_id)
          .and_return(nil)

        # Scheduling workers for the first time
        aggregation_schedule.schedule_root_storage_statistics

        # Executing again, this time workers should not be scheduled
        # due to the lease not been released.
        aggregation_schedule.schedule_root_storage_statistics
      end
    end
  end
end


text:
export default [{
    path: 'api/store/getState',
    method: 'GET',
    name: 'store.getState',
    handler: (req, res) => res(req.lib.store.getState())
}, {
    path: 'api/store/dispatch',
    method: 'POST',
    name: 'store.dispatch',
    handler: (req, res) => {
        req.lib.store.dispatch(req.payload);
        res();
    }
}];


text:
require 'rails_helper'

RSpec.describe ConversationsController, :type => :controller do

end


text:
<InteractableRegion>
</InteractableRegion>


text:
/* ------------------------------------------------------------------------- */
//
// Copyright (c) 2010 CubeSoft, Inc.
//
// Licensed 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.
//
/* ------------------------------------------------------------------------- */
namespace Cube.FileSystem.Tests;

using System;
using System.IO;
using System.Linq;
using Cube.DataContract;
using Cube.Registries.Extensions;
using Cube.Syntax.Extensions;
using Cube.Tests;
using Microsoft.Win32;
using NUnit.Framework;

/* ------------------------------------------------------------------------- */
///
/// DataContractTest
///
/// <summary>
/// Tests methods of the DataContract related classes.
/// </summary>
///
/* ------------------------------------------------------------------------- */
[TestFixture]
class DataContractTest : RegistryFixture
{
    #region Tests

    #region Serialize

    /* --------------------------------------------------------------------- */
    ///
    /// Serialize_File
    ///
    /// <summary>
    /// Tests the Serialize methods with files.
    /// </summary>
    ///
    /* --------------------------------------------------------------------- */
    [TestCase(Format.Xml,  "Person.xml")]
    [TestCase(Format.Json, "Person.json")]
    public void Serialize_File(Format format, string filename)
    {
        var dest = Get(filename);
        format.Serialize(dest, DummyFactory.Create());
        Assert.That(Io.Get(dest).Length, Is.AtLeast(1));
    }

    /* --------------------------------------------------------------------- */
    ///
    /// Serialize_Registry
    ///
    /// <summary>
    /// Tests the Serialize method with the registry subkey.
    /// </summary>
    ///
    /* --------------------------------------------------------------------- */
    [Test]
    public void Serialize_Registry()
    {
        var name = GetKeyName(nameof(Serialize_Registry));

        Format.Registry.Serialize(name, DummyFactory.Create());
        Format.Registry.Serialize(name, default(Dummy)); // ignore

        using var sk = OpenKey(nameof(Serialize_Registry));
        var time = new DateTime(2014, 12, 31, 23, 25, 30, DateTimeKind.Utc);

        Assert.That(sk.GetValue("Name"), Is.EqualTo("山田太郎"));
        Assert.That(sk.GetValue("Age"), Is.EqualTo(15));
        Assert.That(sk.GetValue("Sex"), Is.EqualTo(0));
        Assert.That(sk.GetValue("Reserved"), Is.EqualTo(1));
        Assert.That(sk.GetValue("Creation"), Is.EqualTo(time.ToString("o")));
        Assert.That(sk.GetValue("ID"), Is.EqualTo(123));
        Assert.That(sk.GetValue("Secret"), Is.Null);

        Assert.That(sk.GetValue<string>(@"Contact", "Type"), Is.EqualTo("Phone"));
        Assert.That(sk.GetValue<string>(@"Contact", "Value"), Is.EqualTo("080-9876-5432"));
        Assert.That(sk.GetValue<string>(@"Others\0", "Type"), Is.EqualTo("PC"));
        Assert.That(sk.GetValue<string>(@"Others\0", "Value"), Is.EqualTo("pc@example.com"));
        Assert.That(sk.GetValue<string>(@"Others\1", "Type"), Is.EqualTo("Mobile"));
        Assert.That(sk.GetValue<string>(@"Others\1", "Value"), Is.EqualTo("mobile@example.com"));
        Assert.That(sk.GetValue<string>(@"Messages\0", ""), Is.EqualTo("1st message"));
        Assert.That(sk.GetValue<string>(@"Messages\1", ""), Is.EqualTo("2nd message"));
        Assert.That(sk.GetValue<string>(@"Messages\2", ""), Is.EqualTo("3rd message"));
    }

    /* --------------------------------------------------------------------- */
    ///
    /// Serialize_Registry_Remove
    ///
    /// <summary>
    /// Tests the Serialize method with objects that have a collection.
    /// </summary>
    ///
    /* --------------------------------------------------------------------- */
    [Test]
    public void Serialize_Registry_Remove()
    {
        var name = GetKeyName(nameof(Serialize_Registry_Remove));
        var src  = DummyFactory.Create();

        Format.Registry.Serialize(name, src);
        src.Others.RemoveAt(0);
        Format.Registry.Serialize(name, src);

        var dest = Format.Registry.Deserialize<Dummy>(name);
        Assert.That(dest.Others.Count, Is.EqualTo(1));
    }

    /* --------------------------------------------------------------------- */
    ///
    /// Serialize_Registry_Add
    ///
    /// <summary>
    /// Tests the Serialize method with objects that have a collection.
    /// </summary>
    ///
    /* --------------------------------------------------------------------- */
    [Test]
    public void Serialize_Registry_Add()
    {
        var name = GetKeyName(nameof(Serialize_Registry_Add));
        var src  = DummyFactory.Create();

        Format.Registry.Serialize(name, src);
        src.Messages = 10.Make(i => $"{i}th message").ToArray();
        Format.Registry.Serialize(name, src);

        var dest = Format.Registry.Deserialize<Dummy>(name);
        Assert.That(dest.Messages.Length, Is.EqualTo(10));
    }

    /* --------------------------------------------------------------------- */
    ///
    /// Serialize_Registry_Null
    ///
    /// <summary>
    /// Confirms the behavior when serializing to the invalid registry
    /// subkey.
    /// </summary>
    ///
    /* --------------------------------------------------------------------- */
    [Test]
    public void Serialize_Registry_Null()
    {
        var src  = default(RegistryKey);
        var data = DummyFactory.Create();
        src.Serialize(data); // Does not throw.
    }

    #endregion

    #region Deserialize

    /* --------------------------------------------------------------------- */
    ///
    /// Deserialize_File
    ///
    /// <summary>
    /// Tests the Deserialize methods with files.
    /// </summary>
    ///
    /* --------------------------------------------------------------------- */
    [TestCase(Format.Xml,  "Settings.xml",     ExpectedResult = "John Lennon")]
    [TestCase(Format.Json, "Settings.json",    ExpectedResult = "Mike Davis")]
    [TestCase(Format.Xml,  "Settings.ja.xml",  ExpectedResult = "鈴木一朗")]
    [TestCase(Format.Json, "Settings.ja.json", ExpectedResult = "山田太郎")]
    public string Deserialize_File(Format format, string filename)
    {
        var src = GetSource(filename);
        Assert.That(format.Exists(src), Is.True);

        var dest = format.Deserialize<Dummy>(src);
        dest.Refresh(nameof(dest.Number), nameof(dest.Name));
        return dest.Name;
    }

    /* --------------------------------------------------------------------- */
    ///
    /// Deserialize_File_Brackets
    ///
    /// <summary>
    /// Tests the Deserialize method with a file that contains only "{}".
    /// </summary>
    ///
    /* --------------------------------------------------------------------- */
    [Test]
    public void Deserialize_File_Brackets()
    {
        var src  = GetSource("Brackets.json");
        var dest = Format.Json.Deserialize<Dummy>(src);
        Assert.That(dest, Is.Not.Null);
    }

    /* --------------------------------------------------------------------- */
    ///
    /// Deserialize_File_Empty
    ///
    /// <summary>
    /// Tests the Deserialize methods with an empty file.
    /// </summary>
    ///
    /* --------------------------------------------------------------------- */
    [Test]
    public void Deserialize_File_Empty() => Assert.That(() =>
    {
        var src = Get("Empty.json");
        IoEx.Touch(src);
        _ = Format.Json.Deserialize<Dummy>(src);
    }, Throws.TypeOf<System.Runtime.Serialization.SerializationException>());

    /* --------------------------------------------------------------------- */
    ///
    /// Deserialize_File_NotFound
    ///
    /// <summary>
    /// Tests the Deserialize methods with an inexistent file.
    /// </summary>
    ///
    /* --------------------------------------------------------------------- */
    [Test]
    public void Deserialize_File_NotFound() => Assert.That(
        () => Format.Json.Deserialize<Dummy>(GetSource("not-found.json")),
        Throws.TypeOf<FileNotFoundException>()
    );

    /* --------------------------------------------------------------------- */
    ///
    /// Deserialize_Registry_Null
    ///
    /// <summary>
    /// Confirms the behavior when deserializing from the invalid
    /// registry subkey.
    /// </summary>
    ///
    /* --------------------------------------------------------------------- */
    [Test]
    public void Deserialize_Registry_Null()
    {
        var src  = default(RegistryKey).Deserialize<Dummy>();
        var dest = new Dummy();

        Assert.That(src.Number, Is.EqualTo(dest.Number));
        Assert.That(src.Name,           Is.EqualTo(dest.Name));
        Assert.That(src.Age,            Is.EqualTo(dest.Age));
        Assert.That(src.Sex,            Is.EqualTo(dest.Sex));
        Assert.That(src.Reserved,       Is.EqualTo(dest.Reserved));
        Assert.That(src.Creation,       Is.EqualTo(dest.Creation));
        Assert.That(src.Secret,         Is.EqualTo(dest.Secret));
        Assert.That(src.Contact.Type,   Is.EqualTo(dest.Contact.Type));
        Assert.That(src.Contact.Value,  Is.EqualTo(dest.Contact.Value));
        Assert.That(src.Others.Count,   Is.EqualTo(0));
    }

    #endregion

    /* --------------------------------------------------------------------- */
    ///
    /// Delete_Registry
    ///
    /// <summary>
    /// Tests the Delete extended method for the registry.
    /// </summary>
    ///
    /* --------------------------------------------------------------------- */
    [Test]
    public void Delete_Registry()
    {
        var fmt = Format.Registry;
        var src = GetKeyName(nameof(Delete_Registry));

        Assert.That(fmt.Exists(src), Is.False);
        fmt.Serialize(src, DummyFactory.Create());
        Assert.That(fmt.Exists(src), Is.True);
        fmt.Delete(src);
        fmt.Delete(src); // ignored
        Assert.That(fmt.Exists(src), Is.False);
    }

    /* --------------------------------------------------------------------- */
    ///
    /// Delete_Json
    ///
    /// <summary>
    /// Tests the Delete extended method for the JSON data.
    /// </summary>
    ///
    /* --------------------------------------------------------------------- */
    [Test]
    public void Delete_Json()
    {
        var fmt = Format.Json;
        var src = Get("Settings.json");

        Assert.That(fmt.Exists(src), Is.False);
        Io.Copy(GetSource("Settings.json"), src, true);
        Assert.That(fmt.Exists(src), Is.True);
        fmt.Delete(src);
        fmt.Delete(src);
        Assert.That(fmt.Exists(src), Is.False);
    }

    #endregion
}


text:
.sharepoint-container {
  display: table;
  float: left;
  margin-bottom: 100px;
  margin-left: 5px;
  overflow: auto;
  padding-top: 10px;
  width: 100%;
}
.sharepoint-container table {
  width: 100%;
}
.sharepoint-controls-padding {
  padding-bottom: 10px;
  padding-left: 20px;
  padding-right: 20px;
  padding-top: 10px;
}

#table-sharepoint-folders th {
  height: 40px;
}
#table-sharepoint-items th {
  height: 40px;
}


text:
ACCEPTED

#### According to
The Catalogue of Life, 3rd January 2011

#### Published in
null

#### Original name
Bupleurum subovatum Link ex Spreng.

### Remarks
null


text:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "//www.w3.org/TR/html4/strict.dtd">

<meta name="generator" content="JDiff v1.1.0">

<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
<TITLE>
java.util
</TITLE>
<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />

<nobr>Android Developers | Android.com</nobr>

        API Diff Specification

        To Level:
        24

        From Level:
        23

        Generated
        2016.06.13 13:31

        Statistics

Package java.util

  Added Classes and Interfaces

  <nobr>DoubleSummaryStatistics</nobr>

  <nobr>IntSummaryStatistics</nobr>

  <nobr>Locale.Category</nobr>

  <nobr>LongSummaryStatistics</nobr>

  <nobr>Optional</nobr>

  <nobr>OptionalDouble</nobr>

  <nobr>OptionalInt</nobr>

  <nobr>OptionalLong</nobr>

  <nobr>PrimitiveIterator</nobr>

  <nobr>PrimitiveIterator.OfDouble</nobr>

  <nobr>PrimitiveIterator.OfInt</nobr>

  <nobr>PrimitiveIterator.OfLong</nobr>

  <nobr>Spliterator</nobr>

  <nobr>Spliterator.OfDouble</nobr>

  <nobr>Spliterator.OfInt</nobr>

  <nobr>Spliterator.OfLong</nobr>

  <nobr>Spliterator.OfPrimitive</nobr>

  <nobr>Spliterators</nobr>

  <nobr>Spliterators.AbstractDoubleSpliterator</nobr>

  <nobr>Spliterators.AbstractIntSpliterator</nobr>

  <nobr>Spliterators.AbstractLongSpliterator</nobr>

  <nobr>Spliterators.AbstractSpliterator</nobr>

  <nobr>SplittableRandom</nobr>

  <nobr>StringJoiner</nobr>

  Changed Classes and Interfaces

  <nobr>ArrayDeque</nobr>

  <nobr>ArrayList</nobr>

  <nobr>Arrays</nobr>

  <nobr>BitSet</nobr>

  <nobr>Calendar</nobr>

  <nobr>Collection</nobr>

  <nobr>Collections</nobr>

  <nobr>Comparator</nobr>

  <nobr>Currency</nobr>

  <nobr>EnumMap</nobr>

  <nobr>EventListenerProxy</nobr>

  <nobr>FormatFlagsConversionMismatchException</nobr>

  <nobr>Formattable</nobr>

  <nobr>FormatterClosedException</nobr>

  <nobr>GregorianCalendar</nobr>

  <nobr>HashMap</nobr>

  <nobr>HashSet</nobr>

  <nobr>Hashtable</nobr>

  <nobr>IdentityHashMap</nobr>

  <nobr>IllegalFormatCodePointException</nobr>

  <nobr>IllegalFormatConversionException</nobr>

  <nobr>IllegalFormatException</nobr>

  <nobr>IllegalFormatFlagsException</nobr>

  <nobr>InputMismatchException</nobr>

  <nobr>Iterator</nobr>

  <nobr>LinkedHashMap</nobr>

  <nobr>LinkedList</nobr>

  <nobr>List</nobr>

  <nobr>Locale</nobr>

  <nobr>Map</nobr>

  <nobr>Map.Entry</nobr>

  <nobr>Objects</nobr>

  <nobr>PriorityQueue</nobr>

  <nobr>Random</nobr>

  <nobr>ResourceBundle</nobr>

  <nobr>ResourceBundle.Control</nobr>

  <nobr>Scanner</nobr>

  <nobr>SortedMap</nobr>

  <nobr>TimeZone</nobr>

  <nobr>TreeMap</nobr>

  <nobr>TreeSet</nobr>

  <nobr>Vector</nobr>

  <nobr>WeakHashMap</nobr>

        Except as noted, this content is licensed under
         Creative Commons Attribution 2.5.
        For details and restrictions, see the Content License.

        Site Terms of Service -
        Privacy Policy -
        Brand Guidelines


text:
"""Handler for benchmark.html."""

def web_socket_do_extra_handshake(request):
    # Turn off compression.
    request.ws_extension_processors = []

def web_socket_transfer_data(request):
    data = ''

    while True:
        line = request.ws_stream.receive_message()
        if line is None:
            return

        if isinstance(line, unicode):
            # Respond with a binary data of the specified number of bytes.
            size = int(line)
            if len(data) < size:
                data = 'a' * size
            request.ws_stream.send_message(data, binary=True)
        else:
            # Otherwise, just ack.
            if line != 'a' * len(line):
                return
            request.ws_stream.send_message(str(len(line)));

# vi:sts=4 sw=4 et


text:
from __future__ import unicode_literals

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion

class Migration(migrations.Migration):

    initial = True

    dependencies = [
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
    ]

    operations = [
        migrations.CreateModel(
            name='Like',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('created', models.DateTimeField(auto_now_add=True)),
                ('modified', models.DateTimeField(auto_now=True)),
                ('owner', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
            ],
        ),
        migrations.CreateModel(
            name='Photo',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('caption', models.TextField(max_length=255)),
                ('path', models.TextField(max_length=255)),
                ('created', models.DateTimeField(auto_now_add=True)),
                ('modified', models.DateTimeField(auto_now=True)),
                ('owner', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
            ],
        ),
        migrations.CreateModel(
            name='Tag',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.TextField(max_length=255)),
                ('photo', models.ManyToManyField(to='instaapp.Photo')),
            ],
        ),
        migrations.AddField(
            model_name='like',
            name='photo',
            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='instaapp.Photo'),
        ),
    ]


text:
package DDS;

public final class SchedulingPriorityQosPolicyKindHolder
{
  public DDS.SchedulingPriorityQosPolicyKind value = null;

  public SchedulingPriorityQosPolicyKindHolder ()
  {
  }
}