<commit_before>/*
 *  qiaffine.cpp
 *
 *  Copyright (c) 2015 Tobias Wood.
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#include <iostream>

#include "itkImageIOFactory.h"
#include "itkVersor.h"
#include "itkVersorRigid3DTransform.h"
#include "itkCenteredAffineTransform.h"
#include "itkEuler3DTransform.h"
#include "itkTransformFileWriter.h"
#include "itkPermuteAxesImageFilter.h"
#include "itkFlipImageFilter.h"
#include "itkImageMomentsCalculator.h"

#include "Util.h"
#include "ImageIO.h"
#include "Args.h"

/*
 * Declare arguments here so they are available to pipeline
 */
args::ArgumentParser parser("Applies simple affine transformations to images by manipulating the header\n"
    "transforms. If an output file is not specified, the input file will be\n"
    "overwritten.\n"
    "http://github.com/spinicist/QUIT");

args::Positional<std::string> source_path(parser, "SOURCE", "Source file");
args::Positional<std::string> dest_path(parser, "DEST", "Destination file");

args::HelpFlag help(parser, "HELP", "Show this help menu", {'h', "help"});
args::Flag     verbose(parser, "VERBOSE", "Print more information", {'v', "verbose"});
args::ValueFlag<std::string> center(parser, "CENTER", "Set the origin to geometric center (geo) or (cog)", {'c', "center"});
args::ValueFlag<std::string> tfm_path(parser, "TFM", "Write out the transformation to a file", {'t', "tfm"});
args::ValueFlag<std::string> permute(parser, "PERMUTE", "Permute axes in data-space, e.g. 2,0,1. Negative values mean flip as well", {"permute"});
args::ValueFlag<std::string> flip(parser, "FLIP", "Flip axes in data-space, e.g. 0,1,0. Occurs AFTER any permutation.", {"flip"});
args::ValueFlag<double> scale(parser, "SCALE", "Scale by a constant", {'s', "scale"});
args::ValueFlag<std::string> translate(parser, "TRANSLATE", "Translate image by X,Y,Z (mm)", {"trans"}, "0,0,0");
args::ValueFlag<std::string> rotate(parser, "ROTATE", "Rotate by Euler angles around X,Y,Z (degrees).", {"rotate"}, "0,0,0");

template<typename TImage>
int Pipeline() {
    auto image = QI::ReadImage<TImage>(QI::CheckPos(source_path));

    // Permute if required
    if (permute) {
        auto permute_filter = itk::PermuteAxesImageFilter<TImage>::New();
        itk::FixedArray<unsigned int, TImage::ImageDimension> permute_order;
        std::istringstream iss(permute.Get());
        std::string el;
        for (int i = 0; i < 3; i++) {
            std::getline(iss, el, ',');
            permute_order[i] = std::stoi(el);
        }
        for (int i = 3; i < TImage::ImageDimension; i++) {
            permute_order[i] = i;
        }
        if (!iss)
            QI_FAIL("Failed to read permutation order: " << permute.Get());

        permute_filter->SetInput(image);
        permute_filter->SetOrder(permute_order);
        permute_filter->Update();
        image = permute_filter->GetOutput();
        image->DisconnectPipeline();
    }

    // Flip if required
    if (flip) {
        auto flip_filter = itk::FlipImageFilter<TImage>::New();
        itk::FixedArray<bool, TImage::ImageDimension> flip_axes; // Save this
        std::istringstream iss(flip.Get());
        std::string el;
        for (int i = 0; i < 3; i++) {
            std::getline(iss, el, ',');
            flip_axes[i] = (std::stoi(el) > 0);
        }
        for (int i = 3; i < TImage::ImageDimension; i++) {
            flip_axes[i] = false;
        }
        if (!iss)
            QI_FAIL("Failed to read flip: " << flip.Get());
        if (verbose) std::cout << "Flipping: " << flip_axes << std::endl;
        flip_filter->SetInput(image);
        flip_filter->SetFlipAxes(flip_axes);
        flip_filter->SetFlipAboutOrigin(false);
        flip_filter->Update();
        image = flip_filter->GetOutput();
        image->DisconnectPipeline();
    }

    typename TImage::DirectionType fullDir = image->GetDirection();
    typename TImage::SpacingType fullSpacing = image->GetSpacing();
    typename TImage::PointType fullOrigin = image->GetOrigin();
    typename TImage::SizeType fullSize = image->GetLargestPossibleRegion().GetSize();
    QI::VolumeF::DirectionType direction;
    QI::VolumeF::SpacingType spacing;

    using Affine = itk::CenteredAffineTransform<double, 3>;
    using Euler  = itk::Euler3DTransform<double>;
    Affine::OutputVectorType origin;
    QI::VolumeF::SizeType size;
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            direction[i][j] = fullDir[i][j];
        }
        origin[i] = fullOrigin[i];
        spacing[i] = fullSpacing[i];
        size[i] = fullSize[i];
    }

    auto img_tfm = Affine::New();
    img_tfm->SetMatrix(direction);
    img_tfm->Scale(spacing);
    img_tfm->Translate(origin);
    if (scale) {
        if (verbose) std::cout << "Scaling by factor " << scale.Get() << std::endl;
        img_tfm->Scale(scale.Get());
    }

    auto tfm = Euler::New();
    if (rotate) {
        Eigen::Array3d angles; QI::ArrayArg<Eigen::Array3d, 3>(rotate.Get(), angles);
        tfm->SetRotation(angles[0]*M_PI/180., angles[1]*M_PI/180., angles[2]*M_PI/180.);
        if (verbose) std::cout << "Rotation by: " << angles.transpose() << std::endl;
    }
    if (translate) {
        Euler::OffsetType offset; QI::ArrayArg<Euler::OffsetType, 3>(translate.Get(), offset);
        tfm->Translate(-offset);
        if (verbose) std::cout << "Translate by: " << offset << std::endl;
    }
    if (center) {
        Euler::OffsetType offset; offset.Fill(0.);
        if (center.Get() == "geo") {
            if (verbose) std::cout << "Setting geometric center" << std::endl;
            for (int i = 0; i < 3; i++) {
                offset[i] = origin[i]-spacing[i]*size[i] / 2;
            }
        } else if (center.Get() == "cog") {
            if (verbose) std::cout << "Setting center to center of gravity" << std::endl;
            auto moments = itk::ImageMomentsCalculator<TImage>::New();
            moments->SetImage(image);
            moments->Compute();
            // ITK seems to put a negative sign on the CoG
            for (int i = 0; i < 3; i++) {
                offset[i] = moments->GetCenterOfGravity()[i];
            }
        }
        std::cout << "Translation will be: " << offset << std::endl;
        tfm->Translate(-offset);
    }

    if (tfm_path) { // Output the transform file
        auto writer = itk::TransformFileWriterTemplate<double>::New();
        writer->SetInput(tfm);
        writer->SetFileName(tfm_path.Get());
        if (verbose) std::cout << "Writing transform file: " << tfm_path.Get() << std::endl;
        writer->Update();
    }

    img_tfm->Compose(tfm);
    itk::CenteredAffineTransform<double, 3>::MatrixType fmat = img_tfm->GetMatrix();
    if (verbose) std::cout << "Final transform:\n" << fmat << std::endl;
    for (int i = 0; i < 3; i++) {
        fullOrigin[i] = img_tfm->GetOffset()[i];
    }
    for (int j = 0; j < 3; j++) {
        double scale = 0.;
        for (int i = 0; i < 3; i++) {
            scale += fmat[i][j]*fmat[i][j];
        }
        scale = sqrt(scale);
        for (int i = 0; i < 3; i++) {
            fullDir[i][j] = fmat[i][j] / scale;
        }
    }
    image->SetDirection(fullDir);
    image->SetOrigin(fullOrigin);
    image->SetSpacing(fullSpacing);

    // Write out the edited file
    if (dest_path) {
        if (verbose) std::cout << "Writing: " << dest_path.Get() << std::endl;
        QI::WriteImage(image, dest_path.Get());
    } else {
        if (verbose) std::cout << "Writing: " << source_path.Get() << std::endl;
        QI::WriteImage(image, source_path.Get());
    }
    return EXIT_SUCCESS;
}

int main(int argc, char **argv) {
    QI::ParseArgs(parser, argc, argv, verbose);
    if (verbose) std::cout << "Reading header for: " << QI::CheckPos(source_path) << std::endl;
    auto header = itk::ImageIOFactory::CreateImageIO(QI::CheckPos(source_path).c_str(), itk::ImageIOFactory::ReadMode);
    if (!header)  {
        QI_EXCEPTION("Failed to read header from: " << source_path.Get());
    }
    header->SetFileName(source_path.Get());
    header->ReadImageInformation();
    auto dims  = header->GetNumberOfDimensions();
    auto dtype = header->GetComponentType();
    if (verbose) std::cout << "Datatype is " << header->GetComponentTypeAsString( dtype ) << std::endl;

    #define DIM_SWITCH( TYPE ) \
        switch (dims) { \
            case 3: return Pipeline<itk::Image< TYPE , 3 >>(); \
            case 4: return Pipeline<itk::Image< TYPE , 4 >>(); \
            default: QI_FAIL("Unsupported dimension: " << dims); return EXIT_FAILURE; \
        }

    switch (dtype) {
        case itk::ImageIOBase::UNKNOWNCOMPONENTTYPE: QI_FAIL("Unknown component type in image " << source_path);
        /*case itk::ImageIOBase::UCHAR:  DIM_SWITCH( unsigned char ); break;
        case itk::ImageIOBase::CHAR:   DIM_SWITCH( char ); break;
        case itk::ImageIOBase::USHORT: DIM_SWITCH( unsigned short ); break;
        case itk::ImageIOBase::SHORT:  DIM_SWITCH( short ); break;
        case itk::ImageIOBase::UINT:   DIM_SWITCH( unsigned int ); break;
        case itk::ImageIOBase::INT:    DIM_SWITCH( int ); break;
        case itk::ImageIOBase::ULONG:  DIM_SWITCH( unsigned long ); break;
        case itk::ImageIOBase::LONG:   DIM_SWITCH( long ); break;
        case itk::ImageIOBase::LONGLONG: DIM_SWITCH( long long ); break;
        case itk::ImageIOBase::ULONGLONG: DIM_SWITCH( unsigned long long ); break;*/
        case itk::ImageIOBase::FLOAT:  DIM_SWITCH( float ); break;
        case itk::ImageIOBase::DOUBLE: DIM_SWITCH( double ); break;
        default: QI_FAIL("Unimplemented component type: " << dtype << " in image " << source_path);
    }
}
<commit_msg>BUG: 3048536 introduced a scaling bug in qiaffine<commit_after>/*
 *  qiaffine.cpp
 *
 *  Copyright (c) 2015 Tobias Wood.
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#include <iostream>

#include "itkImageIOFactory.h"
#include "itkVersor.h"
#include "itkVersorRigid3DTransform.h"
#include "itkCenteredAffineTransform.h"
#include "itkEuler3DTransform.h"
#include "itkTransformFileWriter.h"
#include "itkPermuteAxesImageFilter.h"
#include "itkFlipImageFilter.h"
#include "itkImageMomentsCalculator.h"

#include "Util.h"
#include "ImageIO.h"
#include "Args.h"

/*
 * Declare arguments here so they are available to pipeline
 */
args::ArgumentParser parser("Applies simple affine transformations to images by manipulating the header\n"
    "transforms. If an output file is not specified, the input file will be\n"
    "overwritten.\n"
    "http://github.com/spinicist/QUIT");

args::Positional<std::string> source_path(parser, "SOURCE", "Source file");
args::Positional<std::string> dest_path(parser, "DEST", "Destination file");

args::HelpFlag help(parser, "HELP", "Show this help menu", {'h', "help"});
args::Flag     verbose(parser, "VERBOSE", "Print more information", {'v', "verbose"});
args::ValueFlag<std::string> center(parser, "CENTER", "Set the origin to geometric center (geo) or (cog)", {'c', "center"});
args::ValueFlag<std::string> tfm_path(parser, "TFM", "Write out the transformation to a file", {'t', "tfm"});
args::ValueFlag<std::string> permute(parser, "PERMUTE", "Permute axes in data-space, e.g. 2,0,1. Negative values mean flip as well", {"permute"});
args::ValueFlag<std::string> flip(parser, "FLIP", "Flip axes in data-space, e.g. 0,1,0. Occurs AFTER any permutation.", {"flip"});
args::ValueFlag<double> scale(parser, "SCALE", "Scale by a constant", {'s', "scale"}, 1.);
args::ValueFlag<std::string> translate(parser, "TRANSLATE", "Translate image by X,Y,Z (mm)", {"trans"}, "0,0,0");
args::ValueFlag<std::string> rotate(parser, "ROTATE", "Rotate by Euler angles around X,Y,Z (degrees).", {"rotate"}, "0,0,0");

template<typename TImage>
int Pipeline() {
    auto image = QI::ReadImage<TImage>(QI::CheckPos(source_path));

    // Permute if required
    if (permute) {
        auto permute_filter = itk::PermuteAxesImageFilter<TImage>::New();
        itk::FixedArray<unsigned int, TImage::ImageDimension> permute_order;
        std::istringstream iss(permute.Get());
        std::string el;
        for (int i = 0; i < 3; i++) {
            std::getline(iss, el, ',');
            permute_order[i] = std::stoi(el);
        }
        for (int i = 3; i < TImage::ImageDimension; i++) {
            permute_order[i] = i;
        }
        if (!iss)
            QI_FAIL("Failed to read permutation order: " << permute.Get());

        permute_filter->SetInput(image);
        permute_filter->SetOrder(permute_order);
        permute_filter->Update();
        image = permute_filter->GetOutput();
        image->DisconnectPipeline();
    }

    // Flip if required
    if (flip) {
        auto flip_filter = itk::FlipImageFilter<TImage>::New();
        itk::FixedArray<bool, TImage::ImageDimension> flip_axes; // Save this
        std::istringstream iss(flip.Get());
        std::string el;
        for (int i = 0; i < 3; i++) {
            std::getline(iss, el, ',');
            flip_axes[i] = (std::stoi(el) > 0);
        }
        for (int i = 3; i < TImage::ImageDimension; i++) {
            flip_axes[i] = false;
        }
        if (!iss)
            QI_FAIL("Failed to read flip: " << flip.Get());
        if (verbose) std::cout << "Flipping: " << flip_axes << std::endl;
        flip_filter->SetInput(image);
        flip_filter->SetFlipAxes(flip_axes);
        flip_filter->SetFlipAboutOrigin(false);
        flip_filter->Update();
        image = flip_filter->GetOutput();
        image->DisconnectPipeline();
    }

    typename TImage::DirectionType fullDir = image->GetDirection();
    typename TImage::SpacingType fullSpacing = image->GetSpacing();
    typename TImage::PointType fullOrigin = image->GetOrigin();
    typename TImage::SizeType fullSize = image->GetLargestPossibleRegion().GetSize();
    QI::VolumeF::DirectionType direction;
    QI::VolumeF::SpacingType spacing;

    using Affine = itk::CenteredAffineTransform<double, 3>;
    using Euler  = itk::Euler3DTransform<double>;
    Affine::OutputVectorType origin;
    QI::VolumeF::SizeType size;
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            direction[i][j] = fullDir[i][j];
        }
        origin[i] = fullOrigin[i];
        spacing[i] = fullSpacing[i];
        size[i] = fullSize[i];
    }

    auto img_tfm = Affine::New();
    img_tfm->SetMatrix(direction);
    img_tfm->Scale(spacing);
    img_tfm->Translate(origin);
    if (scale) {
        if (verbose) std::cout << "Scaling by factor " << scale.Get() << std::endl;
        img_tfm->Scale(scale.Get());
    }

    auto tfm = Euler::New();
    if (rotate) {
        Eigen::Array3d angles; QI::ArrayArg<Eigen::Array3d, 3>(rotate.Get(), angles);
        tfm->SetRotation(angles[0]*M_PI/180., angles[1]*M_PI/180., angles[2]*M_PI/180.);
        if (verbose) std::cout << "Rotation by: " << angles.transpose() << std::endl;
    }
    if (translate) {
        Euler::OffsetType offset; QI::ArrayArg<Euler::OffsetType, 3>(translate.Get(), offset);
        tfm->Translate(-offset);
        if (verbose) std::cout << "Translate by: " << offset << std::endl;
    }
    if (center) {
        Euler::OffsetType offset; offset.Fill(0.);
        if (center.Get() == "geo") {
            if (verbose) std::cout << "Setting geometric center" << std::endl;
            for (int i = 0; i < 3; i++) {
                offset[i] = origin[i]-spacing[i]*size[i] / 2;
            }
        } else if (center.Get() == "cog") {
            if (verbose) std::cout << "Setting center to center of gravity" << std::endl;
            auto moments = itk::ImageMomentsCalculator<TImage>::New();
            moments->SetImage(image);
            moments->Compute();
            // ITK seems to put a negative sign on the CoG
            for (int i = 0; i < 3; i++) {
                offset[i] = moments->GetCenterOfGravity()[i];
            }
        }
        std::cout << "Translation will be: " << offset << std::endl;
        tfm->Translate(-offset);
    }

    if (tfm_path) { // Output the transform file
        auto writer = itk::TransformFileWriterTemplate<double>::New();
        writer->SetInput(tfm);
        writer->SetFileName(tfm_path.Get());
        if (verbose) std::cout << "Writing transform file: " << tfm_path.Get() << std::endl;
        writer->Update();
    }

    img_tfm->Compose(tfm);
    itk::CenteredAffineTransform<double, 3>::MatrixType fmat = img_tfm->GetMatrix();
    if (verbose) std::cout << "Final transform:\n" << fmat << std::endl;
    for (int i = 0; i < 3; i++) {
        fullOrigin[i] = img_tfm->GetOffset()[i];
    }
    for (int j = 0; j < 3; j++) {
        double mat_scale = 0.;
        for (int i = 0; i < 3; i++) {
            mat_scale += fmat[i][j]*fmat[i][j];
        }
        mat_scale = sqrt(mat_scale);
        for (int i = 0; i < 3; i++) {
            fullDir[i][j] = fmat[i][j] / mat_scale;
        }
    }
    image->SetDirection(fullDir);
    image->SetOrigin(fullOrigin);
    image->SetSpacing(fullSpacing * scale.Get());

    // Write out the edited file
    if (dest_path) {
        if (verbose) std::cout << "Writing: " << dest_path.Get() << std::endl;
        QI::WriteImage(image, dest_path.Get());
    } else {
        if (verbose) std::cout << "Writing: " << source_path.Get() << std::endl;
        QI::WriteImage(image, source_path.Get());
    }
    return EXIT_SUCCESS;
}

int main(int argc, char **argv) {
    QI::ParseArgs(parser, argc, argv, verbose);
    if (verbose) std::cout << "Reading header for: " << QI::CheckPos(source_path) << std::endl;
    auto header = itk::ImageIOFactory::CreateImageIO(QI::CheckPos(source_path).c_str(), itk::ImageIOFactory::ReadMode);
    if (!header)  {
        QI_EXCEPTION("Failed to read header from: " << source_path.Get());
    }
    header->SetFileName(source_path.Get());
    header->ReadImageInformation();
    auto dims  = header->GetNumberOfDimensions();
    auto dtype = header->GetComponentType();
    if (verbose) std::cout << "Datatype is " << header->GetComponentTypeAsString( dtype ) << std::endl;

    #define DIM_SWITCH( TYPE ) \
        switch (dims) { \
            case 3: return Pipeline<itk::Image< TYPE , 3 >>(); \
            case 4: return Pipeline<itk::Image< TYPE , 4 >>(); \
            default: QI_FAIL("Unsupported dimension: " << dims); return EXIT_FAILURE; \
        }

    switch (dtype) {
        case itk::ImageIOBase::UNKNOWNCOMPONENTTYPE: QI_FAIL("Unknown component type in image " << source_path);
        /*case itk::ImageIOBase::UCHAR:  DIM_SWITCH( unsigned char ); break;
        case itk::ImageIOBase::CHAR:   DIM_SWITCH( char ); break;
        case itk::ImageIOBase::USHORT: DIM_SWITCH( unsigned short ); break;
        case itk::ImageIOBase::SHORT:  DIM_SWITCH( short ); break;
        case itk::ImageIOBase::UINT:   DIM_SWITCH( unsigned int ); break;
        case itk::ImageIOBase::INT:    DIM_SWITCH( int ); break;
        case itk::ImageIOBase::ULONG:  DIM_SWITCH( unsigned long ); break;
        case itk::ImageIOBase::LONG:   DIM_SWITCH( long ); break;
        case itk::ImageIOBase::LONGLONG: DIM_SWITCH( long long ); break;
        case itk::ImageIOBase::ULONGLONG: DIM_SWITCH( unsigned long long ); break;*/
        case itk::ImageIOBase::FLOAT:  DIM_SWITCH( float ); break;
        case itk::ImageIOBase::DOUBLE: DIM_SWITCH( double ); break;
        default: QI_FAIL("Unimplemented component type: " << dtype << " in image " << source_path);
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the <organization> nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "CppUTest/TestHarness.h"
#include "CppUTest/TestRegistry.h"
#include "CppUTest/TestOutput.h"
#include "CppUTest/MemoryLeakWarningPlugin.h"
#include "CppUTest/MemoryLeakDetector.h"
#include "CppUTest/TestMemoryAllocator.h"
#include "CppUTest/TestTestingFixture.h"
#include "CppUTest/TestHarness_c.h"

static char* leak1;
static long* leak2;

class DummyReporter: public MemoryLeakFailure
{
public:
	virtual ~DummyReporter()
	{
	}
	virtual void fail(char* /*fail_string*/)
	{
	}
};

static MemoryLeakDetector* detector;
static MemoryLeakWarningPlugin* memPlugin;
static DummyReporter dummy;
static TestMemoryAllocator* allocator;

TEST_GROUP(MemoryLeakWarningTest)
{
	TestTestingFixture* fixture;

	void setup()
	{
		fixture = new TestTestingFixture();
		detector = new MemoryLeakDetector(&dummy);
		allocator = new TestMemoryAllocator;
		memPlugin = new MemoryLeakWarningPlugin("TestMemoryLeakWarningPlugin", detector);
		fixture->registry_->installPlugin(memPlugin);
		memPlugin->enable();

		leak1 = 0;
		leak2 = 0;
	}
	void teardown()
	{
		detector->deallocMemory(allocator, leak1);
		detector->deallocMemory(allocator, leak2);

		delete fixture;
		delete memPlugin;
		delete detector;
		delete allocator;
	}
};

static void _testTwoLeaks()
{
	leak1 = detector->allocMemory(allocator, 10);
	leak2 = (long*) (void*) detector->allocMemory(allocator, 4);
}

TEST(MemoryLeakWarningTest, TwoLeaks)
{
	fixture->setTestFunction(_testTwoLeaks);
	fixture->runAllTests();
	LONGS_EQUAL(1, fixture->getFailureCount());
	fixture->assertPrintContains("Total number of leaks:  2");
}

static void _testIgnore2()
{
	memPlugin->expectLeaksInTest(2);
	leak1 = detector->allocMemory(allocator, 10);
	leak2 = (long*) (void*) detector->allocMemory(allocator, 4);
}

TEST(MemoryLeakWarningTest, Ignore2)
{
	fixture->setTestFunction(_testIgnore2);
	fixture->runAllTests();
	LONGS_EQUAL(0, fixture->getFailureCount());
}

static void _failAndLeakMemory()
{
	leak1 = detector->allocMemory(allocator, 10);
	FAIL("");
}

TEST(MemoryLeakWarningTest, FailingTestDoesNotReportMemoryLeaks)
{
	fixture->setTestFunction(_failAndLeakMemory);
	fixture->runAllTests();
	LONGS_EQUAL(1, fixture->getFailureCount());
}

bool memoryLeakDetectorWasDeleted = false;
bool memoryLeakFailureWasDelete = false;

class DummyMemoryLeakDetector : public MemoryLeakDetector
{
public:
	DummyMemoryLeakDetector(MemoryLeakFailure* reporter) : MemoryLeakDetector(reporter) {}
	virtual ~DummyMemoryLeakDetector()
	{
		memoryLeakDetectorWasDeleted = true;
	}
};

class DummyMemoryLeakFailure : public MemoryLeakFailure
{
	virtual ~DummyMemoryLeakFailure()
	{
		memoryLeakFailureWasDelete = true;
	}
	virtual void fail(char*)
	{
	}
};

static bool cpputestHasCrashed;

TEST_GROUP(MemoryLeakWarningGlobalDetectorTest)
{
	MemoryLeakDetector* detector;
	MemoryLeakFailure* failureReporter;

	DummyMemoryLeakDetector * dummyDetector;
	MemoryLeakFailure* dummyReporter;

	static void crashMethod()
	{
		cpputestHasCrashed = true;
	}

	void setup()
	{
		detector = MemoryLeakWarningPlugin::getGlobalDetector();
		failureReporter = MemoryLeakWarningPlugin::getGlobalFailureReporter();

		memoryLeakDetectorWasDeleted = false;
		memoryLeakFailureWasDelete = false;

		MemoryLeakWarningPlugin::turnOffNewDeleteOverloads();

		dummyReporter = new DummyMemoryLeakFailure;
		dummyDetector = new DummyMemoryLeakDetector(dummyReporter);

		UtestShell::setCrashMethod(crashMethod);
		cpputestHasCrashed = false;
}

	void teardown()
	{
		if (!memoryLeakDetectorWasDeleted) delete dummyDetector;
		if (!memoryLeakFailureWasDelete) delete dummyReporter;

		MemoryLeakWarningPlugin::setGlobalDetector(detector, failureReporter);
		MemoryLeakWarningPlugin::turnOnNewDeleteOverloads();

		UtestShell::resetCrashMethod();

		setCurrentMallocAllocatorToDefault();
		setCurrentNewAllocatorToDefault();
		setCurrentNewArrayAllocatorToDefault();
	}
};

TEST(MemoryLeakWarningGlobalDetectorTest, turnOffNewOverloadsCausesNoAdditionalLeaks)
{
	int storedAmountOfLeaks = detector->totalMemoryLeaks(mem_leak_period_all);

	char* arrayMemory = new char[100];
	char* nonArrayMemory = new char;
	char* mallocMemory = (char*) cpputest_malloc_location_with_leak_detection(10, "file", 10);
	char* reallocMemory = (char*) cpputest_realloc_location_with_leak_detection(NULL, 10, "file", 10);

	LONGS_EQUAL(storedAmountOfLeaks, detector->totalMemoryLeaks(mem_leak_period_all));

	cpputest_free_location_with_leak_detection(mallocMemory, "file", 10);
	cpputest_free_location_with_leak_detection(reallocMemory, "file", 10);
	delete [] arrayMemory;
	delete nonArrayMemory;
}

TEST(MemoryLeakWarningGlobalDetectorTest, destroyGlobalDetector)
{
	MemoryLeakWarningPlugin::setGlobalDetector(dummyDetector, dummyReporter);

	MemoryLeakWarningPlugin::destroyGlobalDetector();

	CHECK(memoryLeakDetectorWasDeleted);
	CHECK(memoryLeakFailureWasDelete);
}

TEST(MemoryLeakWarningGlobalDetectorTest, MemoryWarningPluginCanBeSetToDestroyTheGlobalDetector)
{
	MemoryLeakWarningPlugin* plugin = new MemoryLeakWarningPlugin("dummy");
	plugin->destroyGlobalDetectorAndTurnOffMemoryLeakDetectionInDestructor(true);
	MemoryLeakWarningPlugin::setGlobalDetector(dummyDetector, dummyReporter);

	delete plugin;

	CHECK(memoryLeakDetectorWasDeleted);
}

#ifndef CPPUTEST_MEM_LEAK_DETECTION_DISABLED

TEST(MemoryLeakWarningGlobalDetectorTest, crashOnLeakWithOperatorNew)
{
	MemoryLeakWarningPlugin::setGlobalDetector(dummyDetector, dummyReporter);

	MemoryLeakWarningPlugin::turnOnNewDeleteOverloads();

	crash_on_allocation_number(1);
	char* memory = new char[100];
	CHECK(cpputestHasCrashed);
	delete memory;

	MemoryLeakWarningPlugin::turnOffNewDeleteOverloads();

}

TEST(MemoryLeakWarningGlobalDetectorTest, crashOnLeakWithOperatorNewArray)
{
	MemoryLeakWarningPlugin::setGlobalDetector(dummyDetector, dummyReporter);

	MemoryLeakWarningPlugin::turnOnNewDeleteOverloads();

	crash_on_allocation_number(1);
	char* memory = new char;
	CHECK(cpputestHasCrashed);
	delete memory;

	MemoryLeakWarningPlugin::turnOffNewDeleteOverloads();
}

TEST(MemoryLeakWarningGlobalDetectorTest, crashOnLeakWithOperatorMalloc)
{
	MemoryLeakWarningPlugin::setGlobalDetector(dummyDetector, dummyReporter);

	MemoryLeakWarningPlugin::turnOnNewDeleteOverloads();

	crash_on_allocation_number(1);
	char* memory = (char*) cpputest_malloc(10);
	CHECK(cpputestHasCrashed);
	cpputest_free(memory);

	MemoryLeakWarningPlugin::turnOffNewDeleteOverloads();
}

#endif

#if CPPUTEST_USE_STD_CPP_LIB

TEST(MemoryLeakWarningGlobalDetectorTest, turnOffNewOverloadsNoThrowCausesNoAdditionalLeaks)
{
#undef new
	int storedAmountOfLeaks = detector->totalMemoryLeaks(mem_leak_period_all);

	char* nonMemoryNoThrow = new (std::nothrow) char;
	char* nonArrayMemoryNoThrow = new (std::nothrow) char[10];

	LONGS_EQUAL(storedAmountOfLeaks, detector->totalMemoryLeaks(mem_leak_period_all));

	delete nonMemoryNoThrow;
	delete nonArrayMemoryNoThrow;
#ifdef CPPUTEST_USE_NEW_MACROS
	#include "CppUTest/MemoryLeakDetectorNewMacros.h"
#endif
}

#endif
<commit_msg>And an additional warning<commit_after>/*
 * Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the <organization> nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "CppUTest/TestHarness.h"
#include "CppUTest/TestRegistry.h"
#include "CppUTest/TestOutput.h"
#include "CppUTest/MemoryLeakWarningPlugin.h"
#include "CppUTest/MemoryLeakDetector.h"
#include "CppUTest/TestMemoryAllocator.h"
#include "CppUTest/TestTestingFixture.h"
#include "CppUTest/TestHarness_c.h"

static char* leak1;
static long* leak2;

class DummyReporter: public MemoryLeakFailure
{
public:
	virtual ~DummyReporter()
	{
	}
	virtual void fail(char* /*fail_string*/)
	{
	}
};

static MemoryLeakDetector* detector;
static MemoryLeakWarningPlugin* memPlugin;
static DummyReporter dummy;
static TestMemoryAllocator* allocator;

TEST_GROUP(MemoryLeakWarningTest)
{
	TestTestingFixture* fixture;

	void setup()
	{
		fixture = new TestTestingFixture();
		detector = new MemoryLeakDetector(&dummy);
		allocator = new TestMemoryAllocator;
		memPlugin = new MemoryLeakWarningPlugin("TestMemoryLeakWarningPlugin", detector);
		fixture->registry_->installPlugin(memPlugin);
		memPlugin->enable();

		leak1 = 0;
		leak2 = 0;
	}
	void teardown()
	{
		detector->deallocMemory(allocator, leak1);
		detector->deallocMemory(allocator, leak2);

		delete fixture;
		delete memPlugin;
		delete detector;
		delete allocator;
	}
};

static void _testTwoLeaks()
{
	leak1 = detector->allocMemory(allocator, 10);
	leak2 = (long*) (void*) detector->allocMemory(allocator, 4);
}

TEST(MemoryLeakWarningTest, TwoLeaks)
{
	fixture->setTestFunction(_testTwoLeaks);
	fixture->runAllTests();
	LONGS_EQUAL(1, fixture->getFailureCount());
	fixture->assertPrintContains("Total number of leaks:  2");
}

static void _testIgnore2()
{
	memPlugin->expectLeaksInTest(2);
	leak1 = detector->allocMemory(allocator, 10);
	leak2 = (long*) (void*) detector->allocMemory(allocator, 4);
}

TEST(MemoryLeakWarningTest, Ignore2)
{
	fixture->setTestFunction(_testIgnore2);
	fixture->runAllTests();
	LONGS_EQUAL(0, fixture->getFailureCount());
}

static void _failAndLeakMemory()
{
	leak1 = detector->allocMemory(allocator, 10);
	FAIL("");
}

TEST(MemoryLeakWarningTest, FailingTestDoesNotReportMemoryLeaks)
{
	fixture->setTestFunction(_failAndLeakMemory);
	fixture->runAllTests();
	LONGS_EQUAL(1, fixture->getFailureCount());
}

static bool memoryLeakDetectorWasDeleted = false;
static bool memoryLeakFailureWasDelete = false;

class DummyMemoryLeakDetector : public MemoryLeakDetector
{
public:
	DummyMemoryLeakDetector(MemoryLeakFailure* reporter) : MemoryLeakDetector(reporter) {}
	virtual ~DummyMemoryLeakDetector()
	{
		memoryLeakDetectorWasDeleted = true;
	}
};

class DummyMemoryLeakFailure : public MemoryLeakFailure
{
	virtual ~DummyMemoryLeakFailure()
	{
		memoryLeakFailureWasDelete = true;
	}
	virtual void fail(char*)
	{
	}
};

static bool cpputestHasCrashed;

TEST_GROUP(MemoryLeakWarningGlobalDetectorTest)
{
	MemoryLeakDetector* detector;
	MemoryLeakFailure* failureReporter;

	DummyMemoryLeakDetector * dummyDetector;
	MemoryLeakFailure* dummyReporter;

	static void crashMethod()
	{
		cpputestHasCrashed = true;
	}

	void setup()
	{
		detector = MemoryLeakWarningPlugin::getGlobalDetector();
		failureReporter = MemoryLeakWarningPlugin::getGlobalFailureReporter();

		memoryLeakDetectorWasDeleted = false;
		memoryLeakFailureWasDelete = false;

		MemoryLeakWarningPlugin::turnOffNewDeleteOverloads();

		dummyReporter = new DummyMemoryLeakFailure;
		dummyDetector = new DummyMemoryLeakDetector(dummyReporter);

		UtestShell::setCrashMethod(crashMethod);
		cpputestHasCrashed = false;
}

	void teardown()
	{
		if (!memoryLeakDetectorWasDeleted) delete dummyDetector;
		if (!memoryLeakFailureWasDelete) delete dummyReporter;

		MemoryLeakWarningPlugin::setGlobalDetector(detector, failureReporter);
		MemoryLeakWarningPlugin::turnOnNewDeleteOverloads();

		UtestShell::resetCrashMethod();

		setCurrentMallocAllocatorToDefault();
		setCurrentNewAllocatorToDefault();
		setCurrentNewArrayAllocatorToDefault();
	}
};

TEST(MemoryLeakWarningGlobalDetectorTest, turnOffNewOverloadsCausesNoAdditionalLeaks)
{
	int storedAmountOfLeaks = detector->totalMemoryLeaks(mem_leak_period_all);

	char* arrayMemory = new char[100];
	char* nonArrayMemory = new char;
	char* mallocMemory = (char*) cpputest_malloc_location_with_leak_detection(10, "file", 10);
	char* reallocMemory = (char*) cpputest_realloc_location_with_leak_detection(NULL, 10, "file", 10);

	LONGS_EQUAL(storedAmountOfLeaks, detector->totalMemoryLeaks(mem_leak_period_all));

	cpputest_free_location_with_leak_detection(mallocMemory, "file", 10);
	cpputest_free_location_with_leak_detection(reallocMemory, "file", 10);
	delete [] arrayMemory;
	delete nonArrayMemory;
}

TEST(MemoryLeakWarningGlobalDetectorTest, destroyGlobalDetector)
{
	MemoryLeakWarningPlugin::setGlobalDetector(dummyDetector, dummyReporter);

	MemoryLeakWarningPlugin::destroyGlobalDetector();

	CHECK(memoryLeakDetectorWasDeleted);
	CHECK(memoryLeakFailureWasDelete);
}

TEST(MemoryLeakWarningGlobalDetectorTest, MemoryWarningPluginCanBeSetToDestroyTheGlobalDetector)
{
	MemoryLeakWarningPlugin* plugin = new MemoryLeakWarningPlugin("dummy");
	plugin->destroyGlobalDetectorAndTurnOffMemoryLeakDetectionInDestructor(true);
	MemoryLeakWarningPlugin::setGlobalDetector(dummyDetector, dummyReporter);

	delete plugin;

	CHECK(memoryLeakDetectorWasDeleted);
}

#ifndef CPPUTEST_MEM_LEAK_DETECTION_DISABLED

TEST(MemoryLeakWarningGlobalDetectorTest, crashOnLeakWithOperatorNew)
{
	MemoryLeakWarningPlugin::setGlobalDetector(dummyDetector, dummyReporter);

	MemoryLeakWarningPlugin::turnOnNewDeleteOverloads();

	crash_on_allocation_number(1);
	char* memory = new char[100];
	CHECK(cpputestHasCrashed);
	delete memory;

	MemoryLeakWarningPlugin::turnOffNewDeleteOverloads();

}

TEST(MemoryLeakWarningGlobalDetectorTest, crashOnLeakWithOperatorNewArray)
{
	MemoryLeakWarningPlugin::setGlobalDetector(dummyDetector, dummyReporter);

	MemoryLeakWarningPlugin::turnOnNewDeleteOverloads();

	crash_on_allocation_number(1);
	char* memory = new char;
	CHECK(cpputestHasCrashed);
	delete memory;

	MemoryLeakWarningPlugin::turnOffNewDeleteOverloads();
}

TEST(MemoryLeakWarningGlobalDetectorTest, crashOnLeakWithOperatorMalloc)
{
	MemoryLeakWarningPlugin::setGlobalDetector(dummyDetector, dummyReporter);

	MemoryLeakWarningPlugin::turnOnNewDeleteOverloads();

	crash_on_allocation_number(1);
	char* memory = (char*) cpputest_malloc(10);
	CHECK(cpputestHasCrashed);
	cpputest_free(memory);

	MemoryLeakWarningPlugin::turnOffNewDeleteOverloads();
}

#endif

#if CPPUTEST_USE_STD_CPP_LIB

TEST(MemoryLeakWarningGlobalDetectorTest, turnOffNewOverloadsNoThrowCausesNoAdditionalLeaks)
{
#undef new
	int storedAmountOfLeaks = detector->totalMemoryLeaks(mem_leak_period_all);

	char* nonMemoryNoThrow = new (std::nothrow) char;
	char* nonArrayMemoryNoThrow = new (std::nothrow) char[10];

	LONGS_EQUAL(storedAmountOfLeaks, detector->totalMemoryLeaks(mem_leak_period_all));

	delete nonMemoryNoThrow;
	delete nonArrayMemoryNoThrow;
#ifdef CPPUTEST_USE_NEW_MACROS
	#include "CppUTest/MemoryLeakDetectorNewMacros.h"
#endif
}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2019.  All rights reserved
 */
#ifndef _Stroika_Foundation_IO_Network_URL_UniformResourceIdentification_
#define _Stroika_Foundation_IO_Network_URL_UniformResourceIdentification_ 1

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
#include "../../Memory/Optional.h"

namespace Stroika::Foundation::IO::Network::UniformResourceIdentification {

    /*
     ********************************************************************************
     ******************* UniformResourceIdentification::SchemeType ******************
     ********************************************************************************
     */
    inline SchemeType::SchemeType (const wchar_t* s)
        : inherited{s}
    {
    }
    inline SchemeType::SchemeType (const wstring_view& s)
        : inherited{s}
    {
    }
    inline SchemeType::SchemeType (const String& s)
        : inherited{s}
    {
    }

    /*
     ********************************************************************************
     ************************* SchemeType::ThreeWayComparer *************************
     ********************************************************************************
     */
    constexpr SchemeType::ThreeWayComparer::ThreeWayComparer ()
        : String::ThreeWayComparer{Characters::CompareOptions::eCaseInsensitive}
    {
    }

    /*
     ********************************************************************************
     **************************** SchemeType operators ******************************
     ********************************************************************************
     */
    inline bool operator< (const SchemeType& lhs, const SchemeType& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) < 0;
    }
    inline bool operator<= (const SchemeType& lhs, const SchemeType& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) <= 0;
    }
    inline bool operator== (const SchemeType& lhs, const SchemeType& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) == 0;
    }
    inline bool operator!= (const SchemeType& lhs, const SchemeType& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) != 0;
    }
    inline bool operator>= (const SchemeType& lhs, const SchemeType& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) >= 0;
    }
    inline bool operator> (const SchemeType& lhs, const SchemeType& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) > 0;
    }

    /*
     ********************************************************************************
     ************************************* Host *************************************
     ********************************************************************************
     */
    inline Host::Host (const String& registeredName)
        : fEncodedName_{EncodeAsRawURL_ (registeredName)}
        , fRegisteredName_{registeredName}
    {
        Require (not registeredName.empty ());
    }
    inline Host::Host (const InternetAddress& addr)
        : fEncodedName_{EncodeAsRawURL_ (addr)}
        , fInternetAddress_{addr}
    {
    }
    inline Host Host::Parse (const String& rawURLHostnameText)
    {
        Require (not rawURLHostnameText.empty ());
        pair<optional<String>, optional<InternetAddress>> tmp{ParseRaw_ (rawURLHostnameText)};
        Host                                              h;
        h.fEncodedName_     = rawURLHostnameText;
        h.fRegisteredName_  = tmp.first;
        h.fInternetAddress_ = tmp.second;
        return h;
    }
    inline optional<String> Host::AsRegisteredName () const
    {
        return fRegisteredName_;
    }
    inline optional<InternetAddress> Host::AsInternetAddress () const
    {
        return fInternetAddress_;
    }
    inline String Host::AsDecoded () const
    {
        if (fRegisteredName_) {
            return *fRegisteredName_;
        }
        Assert (fInternetAddress_);
        return fInternetAddress_->As<String> ();
    }
    template <>
    inline String Host::AsEncoded () const
    {
        return fEncodedName_;
    }
    template <>
    inline string Host::AsEncoded () const
    {
        return fEncodedName_.AsASCII<string> ();
    }

    /*
     ********************************************************************************
     ************************** Host::ThreeWayComparer ******************************
     ********************************************************************************
     */
    inline int Host::ThreeWayComparer::operator() (const Host& lhs, const Host& rhs) const
    {
        if (int cmp = Common::ThreeWayCompare (lhs.AsInternetAddress (), rhs.AsInternetAddress ())) {
            return cmp;
        }
        return Common::OptionalThreeWayCompare<String, String::ThreeWayComparer>{
            String::ThreeWayComparer{Characters::CompareOptions::eCaseInsensitive}}(lhs.AsRegisteredName (), rhs.AsRegisteredName ());
    }

    /*
     ********************************************************************************
     ******************************** Host operators ********************************
     ********************************************************************************
     */
    inline bool operator< (const Host& lhs, const Host& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) < 0;
    }
    inline bool operator<= (const Host& lhs, const Host& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) <= 0;
    }
    inline bool operator== (const Host& lhs, const Host& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) == 0;
    }
    inline bool operator!= (const Host& lhs, const Host& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) != 0;
    }
    inline bool operator>= (const Host& lhs, const Host& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) >= 0;
    }
    inline bool operator> (const Host& lhs, const Host& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) > 0;
    }

    /*
     ********************************************************************************
     ********************************* UserInfo *************************************
     ********************************************************************************
     */
    inline UserInfo::UserInfo (const String& decodedUserInfo)
        : fEncodedUserInfo_{EncodeAsRawURL_ (decodedUserInfo)}
        , fUserInfo_{decodedUserInfo}
    {
        Require (not decodedUserInfo.empty ());
    }
    inline UserInfo UserInfo::Parse (const String& rawURLUserInfo)
    {
        Require (not rawURLUserInfo.empty ());
        UserInfo h;
        h.fEncodedUserInfo_ = rawURLUserInfo;
        h.fUserInfo_        = ParseRaw_ (rawURLUserInfo);
        return h;
    }
    inline String UserInfo::AsDecoded () const
    {
        return fUserInfo_;
    }
    template <>
    inline String UserInfo::AsEncoded () const
    {
        return fEncodedUserInfo_;
    }
    template <>
    inline string UserInfo::AsEncoded () const
    {
        return fEncodedUserInfo_.AsASCII<string> ();
    }

    /*
     ********************************************************************************
     *********************** UserInfo::ThreeWayComparer *****************************
     ********************************************************************************
     */
    inline int UserInfo::ThreeWayComparer::operator() (const UserInfo& lhs, const UserInfo& rhs) const
    {
        return Common::ThreeWayCompare (lhs.AsDecoded (), rhs.AsDecoded ());
    }

    /*
     ********************************************************************************
     ****************************** UserInfo operators ******************************
     ********************************************************************************
     */
    inline bool operator< (const UserInfo& lhs, const UserInfo& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) < 0;
    }
    inline bool operator<= (const UserInfo& lhs, const UserInfo& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) <= 0;
    }
    inline bool operator== (const UserInfo& lhs, const UserInfo& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) == 0;
    }
    inline bool operator!= (const UserInfo& lhs, const UserInfo& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) != 0;
    }
    inline bool operator>= (const UserInfo& lhs, const UserInfo& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) >= 0;
    }
    inline bool operator> (const UserInfo& lhs, const UserInfo& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) > 0;
    }

    /*
     ********************************************************************************
     ********************************* Authority ************************************
     ********************************************************************************
     */
    inline Authority::Authority (const optional<Host>& h, const optional<PortType>& port, const optional<UserInfo>& userInfo)
        : fHost_{h}
        , fPort_{port}
        , fUserInfo_{userInfo}
    {
    }
    inline optional<Host> Authority::GetHost () const
    {
        return fHost_;
    }
    inline void Authority::SetHost (const optional<Host>& host)
    {
        fHost_ = host;
    }
    inline optional<PortType> Authority::GetPort () const
    {
        return fPort_;
    }
    inline void Authority::SetPort (const optional<PortType>& port)
    {
        fPort_ = port;
    }
    inline optional<UserInfo> Authority::GetUserInfo () const
    {
        return fUserInfo_;
    }
    inline void Authority::SetUserInfo (const optional<UserInfo>& userInfo)
    {
        fUserInfo_ = userInfo;
    }

    /*
     ********************************************************************************
     ************************ ThreeWayComparer<Authority> ***************************
     ********************************************************************************
     */
    inline int Authority::ThreeWayComparer::operator() (const Authority& lhs, const Authority& rhs) const
    {
        if (int cmp = Common::ThreeWayCompare (lhs.GetHost (), rhs.GetHost ())) {
            return cmp;
        }
        if (int cmp = Common::ThreeWayCompare (lhs.GetUserInfo (), rhs.GetUserInfo ())) {
            return cmp;
        }
        return Common::ThreeWayCompare (lhs.GetPort (), rhs.GetPort ());
    }

    /*
     ********************************************************************************
     *********************** Authority comparison operators *************************
     ********************************************************************************
     */
    inline bool operator< (const Authority& lhs, const Authority& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) < 0;
    }
    inline bool operator<= (const Authority& lhs, const Authority& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) <= 0;
    }
    inline bool operator== (const Authority& lhs, const Authority& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) == 0;
    }
    inline bool operator!= (const Authority& lhs, const Authority& rhs)
    {
        return not Common::ThreeWayCompare (lhs, rhs) == 0;
    }
    inline bool operator>= (const Authority& lhs, const Authority& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) >= 0;
    }
    inline bool operator> (const Authority& lhs, const Authority& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) > 0;
    }

    /*
     ********************************************************************************
     ************************************ Query *************************************
     ********************************************************************************
     */
    inline const Containers::Mapping<String, String>& Query::GetMap () const
    {
        return fMap_;
    }
    inline String Query::operator() (const String& idx) const
    {
        return Memory::ValueOrDefault (fMap_.Lookup (idx));
    }
    inline String Query::operator() (const string& idx) const
    {
        return operator() (Characters::UTF8StringToWide (idx));
    }
    inline bool Query::HasField (const String& idx) const
    {
        return fMap_.ContainsKey (idx);
    }
    inline bool Query::HasField (const string& idx) const
    {
        return HasField (Characters::UTF8StringToWide (idx));
    }
    inline void Query::AddField (const String& idx, const String& value)
    {
        fMap_.Add (idx, value);
    }
    inline void Query::RemoveFieldIfAny (const string& idx)
    {
        RemoveFieldIfAny (Characters::UTF8StringToWide (idx));
    }

    /*
     ********************************************************************************
     **************************** Query::operators **********************************
     ********************************************************************************
     */
    inline bool operator< (const Query& lhs, const Query& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) < 0;
    }
    inline bool operator<= (const Query& lhs, const Query& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) <= 0;
    }
    inline bool operator== (const Query& lhs, const Query& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) == 0;
    }
    inline bool operator!= (const Query& lhs, const Query& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) != 0;
    }
    inline bool operator>= (const Query& lhs, const Query& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) >= 0;
    }
    inline bool operator> (const Query& lhs, const Query& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) > 0;
    }

}

#endif /*_Stroika_Foundation_IO_Network_URL_UniformResourceIdentification_*/
<commit_msg>fixed typo<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2019.  All rights reserved
 */
#ifndef _Stroika_Foundation_IO_Network_URL_UniformResourceIdentification_
#define _Stroika_Foundation_IO_Network_URL_UniformResourceIdentification_ 1

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
#include "../../Memory/Optional.h"

namespace Stroika::Foundation::IO::Network::UniformResourceIdentification {

    /*
     ********************************************************************************
     ******************* UniformResourceIdentification::SchemeType ******************
     ********************************************************************************
     */
    inline SchemeType::SchemeType (const wchar_t* s)
        : inherited{s}
    {
    }
    inline SchemeType::SchemeType (const wstring_view& s)
        : inherited{s}
    {
    }
    inline SchemeType::SchemeType (const String& s)
        : inherited{s}
    {
    }

    /*
     ********************************************************************************
     ************************* SchemeType::ThreeWayComparer *************************
     ********************************************************************************
     */
    constexpr SchemeType::ThreeWayComparer::ThreeWayComparer ()
        : String::ThreeWayComparer{Characters::CompareOptions::eCaseInsensitive}
    {
    }

    /*
     ********************************************************************************
     **************************** SchemeType operators ******************************
     ********************************************************************************
     */
    inline bool operator< (const SchemeType& lhs, const SchemeType& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) < 0;
    }
    inline bool operator<= (const SchemeType& lhs, const SchemeType& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) <= 0;
    }
    inline bool operator== (const SchemeType& lhs, const SchemeType& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) == 0;
    }
    inline bool operator!= (const SchemeType& lhs, const SchemeType& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) != 0;
    }
    inline bool operator>= (const SchemeType& lhs, const SchemeType& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) >= 0;
    }
    inline bool operator> (const SchemeType& lhs, const SchemeType& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) > 0;
    }

    /*
     ********************************************************************************
     ************************************* Host *************************************
     ********************************************************************************
     */
    inline Host::Host (const String& registeredName)
        : fEncodedName_{EncodeAsRawURL_ (registeredName)}
        , fRegisteredName_{registeredName}
    {
        Require (not registeredName.empty ());
    }
    inline Host::Host (const InternetAddress& addr)
        : fEncodedName_{EncodeAsRawURL_ (addr)}
        , fInternetAddress_{addr}
    {
    }
    inline Host Host::Parse (const String& rawURLHostnameText)
    {
        Require (not rawURLHostnameText.empty ());
        pair<optional<String>, optional<InternetAddress>> tmp{ParseRaw_ (rawURLHostnameText)};
        Host                                              h;
        h.fEncodedName_     = rawURLHostnameText;
        h.fRegisteredName_  = tmp.first;
        h.fInternetAddress_ = tmp.second;
        return h;
    }
    inline optional<String> Host::AsRegisteredName () const
    {
        return fRegisteredName_;
    }
    inline optional<InternetAddress> Host::AsInternetAddress () const
    {
        return fInternetAddress_;
    }
    inline String Host::AsDecoded () const
    {
        if (fRegisteredName_) {
            return *fRegisteredName_;
        }
        Assert (fInternetAddress_);
        return fInternetAddress_->As<String> ();
    }
    template <>
    inline String Host::AsEncoded () const
    {
        return fEncodedName_;
    }
    template <>
    inline string Host::AsEncoded () const
    {
        return fEncodedName_.AsASCII<string> ();
    }

    /*
     ********************************************************************************
     ************************** Host::ThreeWayComparer ******************************
     ********************************************************************************
     */
    inline int Host::ThreeWayComparer::operator() (const Host& lhs, const Host& rhs) const
    {
        if (int cmp = Common::ThreeWayCompare (lhs.AsInternetAddress (), rhs.AsInternetAddress ())) {
            return cmp;
        }
        return Common::OptionalThreeWayCompare<String, String::ThreeWayComparer>{
            String::ThreeWayComparer{Characters::CompareOptions::eCaseInsensitive}}(lhs.AsRegisteredName (), rhs.AsRegisteredName ());
    }

    /*
     ********************************************************************************
     ******************************** Host operators ********************************
     ********************************************************************************
     */
    inline bool operator< (const Host& lhs, const Host& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) < 0;
    }
    inline bool operator<= (const Host& lhs, const Host& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) <= 0;
    }
    inline bool operator== (const Host& lhs, const Host& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) == 0;
    }
    inline bool operator!= (const Host& lhs, const Host& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) != 0;
    }
    inline bool operator>= (const Host& lhs, const Host& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) >= 0;
    }
    inline bool operator> (const Host& lhs, const Host& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) > 0;
    }

    /*
     ********************************************************************************
     ********************************* UserInfo *************************************
     ********************************************************************************
     */
    inline UserInfo::UserInfo (const String& decodedUserInfo)
        : fEncodedUserInfo_{EncodeAsRawURL_ (decodedUserInfo)}
        , fUserInfo_{decodedUserInfo}
    {
        Require (not decodedUserInfo.empty ());
    }
    inline UserInfo UserInfo::Parse (const String& rawURLUserInfo)
    {
        Require (not rawURLUserInfo.empty ());
        UserInfo h;
        h.fEncodedUserInfo_ = rawURLUserInfo;
        h.fUserInfo_        = ParseRaw_ (rawURLUserInfo);
        return h;
    }
    inline String UserInfo::AsDecoded () const
    {
        return fUserInfo_;
    }
    template <>
    inline String UserInfo::AsEncoded () const
    {
        return fEncodedUserInfo_;
    }
    template <>
    inline string UserInfo::AsEncoded () const
    {
        return fEncodedUserInfo_.AsASCII<string> ();
    }

    /*
     ********************************************************************************
     *********************** UserInfo::ThreeWayComparer *****************************
     ********************************************************************************
     */
    inline int UserInfo::ThreeWayComparer::operator() (const UserInfo& lhs, const UserInfo& rhs) const
    {
        return Common::ThreeWayCompare (lhs.AsDecoded (), rhs.AsDecoded ());
    }

    /*
     ********************************************************************************
     ****************************** UserInfo operators ******************************
     ********************************************************************************
     */
    inline bool operator< (const UserInfo& lhs, const UserInfo& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) < 0;
    }
    inline bool operator<= (const UserInfo& lhs, const UserInfo& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) <= 0;
    }
    inline bool operator== (const UserInfo& lhs, const UserInfo& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) == 0;
    }
    inline bool operator!= (const UserInfo& lhs, const UserInfo& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) != 0;
    }
    inline bool operator>= (const UserInfo& lhs, const UserInfo& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) >= 0;
    }
    inline bool operator> (const UserInfo& lhs, const UserInfo& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) > 0;
    }

    /*
     ********************************************************************************
     ********************************* Authority ************************************
     ********************************************************************************
     */
    inline Authority::Authority (const optional<Host>& h, const optional<PortType>& port, const optional<UserInfo>& userInfo)
        : fHost_{h}
        , fPort_{port}
        , fUserInfo_{userInfo}
    {
    }
    inline optional<Host> Authority::GetHost () const
    {
        return fHost_;
    }
    inline void Authority::SetHost (const optional<Host>& host)
    {
        fHost_ = host;
    }
    inline optional<PortType> Authority::GetPort () const
    {
        return fPort_;
    }
    inline void Authority::SetPort (const optional<PortType>& port)
    {
        fPort_ = port;
    }
    inline optional<UserInfo> Authority::GetUserInfo () const
    {
        return fUserInfo_;
    }
    inline void Authority::SetUserInfo (const optional<UserInfo>& userInfo)
    {
        fUserInfo_ = userInfo;
    }

    /*
     ********************************************************************************
     ************************ ThreeWayComparer<Authority> ***************************
     ********************************************************************************
     */
    inline int Authority::ThreeWayComparer::operator() (const Authority& lhs, const Authority& rhs) const
    {
        if (int cmp = Common::ThreeWayCompare (lhs.GetHost (), rhs.GetHost ())) {
            return cmp;
        }
        if (int cmp = Common::ThreeWayCompare (lhs.GetUserInfo (), rhs.GetUserInfo ())) {
            return cmp;
        }
        return Common::ThreeWayCompare (lhs.GetPort (), rhs.GetPort ());
    }

    /*
     ********************************************************************************
     *********************** Authority comparison operators *************************
     ********************************************************************************
     */
    inline bool operator< (const Authority& lhs, const Authority& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) < 0;
    }
    inline bool operator<= (const Authority& lhs, const Authority& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) <= 0;
    }
    inline bool operator== (const Authority& lhs, const Authority& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) == 0;
    }
    inline bool operator!= (const Authority& lhs, const Authority& rhs)
    {
        return  Common::ThreeWayCompare (lhs, rhs) != 0;
    }
    inline bool operator>= (const Authority& lhs, const Authority& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) >= 0;
    }
    inline bool operator> (const Authority& lhs, const Authority& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) > 0;
    }

    /*
     ********************************************************************************
     ************************************ Query *************************************
     ********************************************************************************
     */
    inline const Containers::Mapping<String, String>& Query::GetMap () const
    {
        return fMap_;
    }
    inline String Query::operator() (const String& idx) const
    {
        return Memory::ValueOrDefault (fMap_.Lookup (idx));
    }
    inline String Query::operator() (const string& idx) const
    {
        return operator() (Characters::UTF8StringToWide (idx));
    }
    inline bool Query::HasField (const String& idx) const
    {
        return fMap_.ContainsKey (idx);
    }
    inline bool Query::HasField (const string& idx) const
    {
        return HasField (Characters::UTF8StringToWide (idx));
    }
    inline void Query::AddField (const String& idx, const String& value)
    {
        fMap_.Add (idx, value);
    }
    inline void Query::RemoveFieldIfAny (const string& idx)
    {
        RemoveFieldIfAny (Characters::UTF8StringToWide (idx));
    }

    /*
     ********************************************************************************
     **************************** Query::operators **********************************
     ********************************************************************************
     */
    inline bool operator< (const Query& lhs, const Query& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) < 0;
    }
    inline bool operator<= (const Query& lhs, const Query& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) <= 0;
    }
    inline bool operator== (const Query& lhs, const Query& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) == 0;
    }
    inline bool operator!= (const Query& lhs, const Query& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) != 0;
    }
    inline bool operator>= (const Query& lhs, const Query& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) >= 0;
    }
    inline bool operator> (const Query& lhs, const Query& rhs)
    {
        return Common::ThreeWayCompare (lhs, rhs) > 0;
    }

}

#endif /*_Stroika_Foundation_IO_Network_URL_UniformResourceIdentification_*/
<|endoftext|>


<commit_before>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "apps/shell_window_geometry_cache.h"
#include "chrome/browser/apps/app_browsertest_util.h"
#include "chrome/browser/extensions/extension_test_message_listener.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/extensions/application_launch.h"
#include "content/public/browser/notification_service.h"
#include "content/public/test/test_utils.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"

using apps::ShellWindowGeometryCache;

// This helper class can be used to wait for changes in the shell window
// geometry cache registry for a specific window in a specific extension.
class GeometryCacheChangeHelper : ShellWindowGeometryCache::Observer {
 public:
  GeometryCacheChangeHelper(ShellWindowGeometryCache* cache,
                            const std::string& extension_id,
                            const std::string& window_id,
                            const gfx::Rect& bounds)
      : cache_(cache),
        extension_id_(extension_id),
        window_id_(window_id),
        bounds_(bounds) {
    cache_->AddObserver(this);
  }

  // This method will block until the shell window geometry cache registry will
  // provide a bound for |window_id_| that is entirely different (as in x/y/w/h)
  // from the initial |bounds_|.
  void WaitForEntirelyChanged() {
    content::RunMessageLoop();
  }

  // Implements the content::NotificationObserver interface.
  virtual void OnGeometryCacheChanged(const std::string& extension_id,
                                      const std::string& window_id,
                                      const gfx::Rect& bounds)
      OVERRIDE {
    if (extension_id != extension_id_ || window_id != window_id_)
      return;

    if (bounds_.x() != bounds.x() &&
        bounds_.y() != bounds.y() &&
        bounds_.width() != bounds.width() &&
        bounds_.height() != bounds.height()) {
      cache_->RemoveObserver(this);
      base::MessageLoopForUI::current()->Quit();
    }
  }

 private:
  ShellWindowGeometryCache* cache_;
  std::string extension_id_;
  std::string window_id_;
  gfx::Rect bounds_;
};

// Helper class for tests related to the Apps Window API (chrome.app.window).
class AppWindowAPI : public extensions::PlatformAppBrowserTest {
 public:
  bool RunAppWindowAPITest(const char* testName) {
    ExtensionTestMessageListener launched_listener("Launched", true);
    LoadAndLaunchPlatformApp("window_api");
    if (!launched_listener.WaitUntilSatisfied()) {
      message_ = "Did not get the 'Launched' message.";
      return false;
    }

    ResultCatcher catcher;
    launched_listener.Reply(testName);

    if (!catcher.GetNextResult()) {
      message_ = catcher.message();
      return false;
    }

    return true;
  }
};

// These tests are flaky after https://codereview.chromium.org/57433010/.
// See http://crbug.com/319613.

IN_PROC_BROWSER_TEST_F(AppWindowAPI, DISABLED_TestCreate) {
  ASSERT_TRUE(RunAppWindowAPITest("testCreate")) << message_;
}

IN_PROC_BROWSER_TEST_F(AppWindowAPI, DISABLED_TestSingleton) {
  ASSERT_TRUE(RunAppWindowAPITest("testSingleton")) << message_;
}

IN_PROC_BROWSER_TEST_F(AppWindowAPI, DISABLED_TestBounds) {
  ASSERT_TRUE(RunAppWindowAPITest("testBounds")) << message_;
}

IN_PROC_BROWSER_TEST_F(AppWindowAPI, DISABLED_TestCloseEvent) {
  ASSERT_TRUE(RunAppWindowAPITest("testCloseEvent")) << message_;
}

IN_PROC_BROWSER_TEST_F(AppWindowAPI, DISABLED_TestMaximize) {
  ASSERT_TRUE(RunAppWindowAPITest("testMaximize")) << message_;
}

IN_PROC_BROWSER_TEST_F(AppWindowAPI, DISABLED_TestRestore) {
  ASSERT_TRUE(RunAppWindowAPITest("testRestore")) << message_;
}

IN_PROC_BROWSER_TEST_F(AppWindowAPI, DISABLED_TestRestoreAfterClose) {
  ASSERT_TRUE(RunAppWindowAPITest("testRestoreAfterClose")) << message_;
}

// Flaky failures on mac_rel, see http://crbug.com/324915
#if defined(OS_MACOSX)
#define MAYBE_TestRestoreGeometryCacheChange DISABLED_TestRestoreGeometryCacheChange
#else
#define MAYBE_TestRestoreGeometryCacheChange TestRestoreGeometryCacheChange
#endif
IN_PROC_BROWSER_TEST_F(AppWindowAPI, MAYBE_TestRestoreGeometryCacheChange) {
  // This test is similar to the other AppWindowAPI tests except that at some
  // point the app will send a 'ListenGeometryChange' message at which point the
  // test will check if the geometry cache entry for the test window has
  // changed. When the change happens, the test will let the app know so it can
  // continue running.
  ExtensionTestMessageListener launched_listener("Launched", true);

  content::WindowedNotificationObserver app_loaded_observer(
      content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
      content::NotificationService::AllSources());

  const extensions::Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("platform_apps").AppendASCII("window_api"));
  EXPECT_TRUE(extension);

  OpenApplication(AppLaunchParams(browser()->profile(),
                                  extension,
                                  extensions::LAUNCH_CONTAINER_NONE,
                                  NEW_WINDOW));

  ExtensionTestMessageListener geometry_listener("ListenGeometryChange", true);

  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
  launched_listener.Reply("testRestoreAfterGeometryCacheChange");

  ASSERT_TRUE(geometry_listener.WaitUntilSatisfied());

  GeometryCacheChangeHelper geo_change_helper(
      ShellWindowGeometryCache::Get(browser()->profile()), extension->id(),
      // The next line has information that has to stay in sync with the app.
      "test-ps", gfx::Rect(200, 200, 200, 200));

  // This call will block until the shell window geometry cache will be changed.
  geo_change_helper.WaitForEntirelyChanged();

  ResultCatcher catcher;
  geometry_listener.Reply("");
  ASSERT_TRUE(catcher.GetNextResult());
}

IN_PROC_BROWSER_TEST_F(AppWindowAPI, DISABLED_TestSizeConstraints) {
  ASSERT_TRUE(RunAppWindowAPITest("testSizeConstraints")) << message_;
}
<commit_msg>Revert 240112 "Revert of https://codereview.chromium.org/104333002/"<commit_after>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "apps/shell_window_geometry_cache.h"
#include "chrome/browser/apps/app_browsertest_util.h"
#include "chrome/browser/extensions/extension_test_message_listener.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/extensions/application_launch.h"
#include "content/public/browser/notification_service.h"
#include "content/public/test/test_utils.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"

using apps::ShellWindowGeometryCache;

// This helper class can be used to wait for changes in the shell window
// geometry cache registry for a specific window in a specific extension.
class GeometryCacheChangeHelper : ShellWindowGeometryCache::Observer {
 public:
  GeometryCacheChangeHelper(ShellWindowGeometryCache* cache,
                            const std::string& extension_id,
                            const std::string& window_id,
                            const gfx::Rect& bounds)
      : cache_(cache),
        extension_id_(extension_id),
        window_id_(window_id),
        bounds_(bounds) {
    cache_->AddObserver(this);
  }

  // This method will block until the shell window geometry cache registry will
  // provide a bound for |window_id_| that is entirely different (as in x/y/w/h)
  // from the initial |bounds_|.
  void WaitForEntirelyChanged() {
    content::RunMessageLoop();
  }

  // Implements the content::NotificationObserver interface.
  virtual void OnGeometryCacheChanged(const std::string& extension_id,
                                      const std::string& window_id,
                                      const gfx::Rect& bounds)
      OVERRIDE {
    if (extension_id != extension_id_ || window_id != window_id_)
      return;

    if (bounds_.x() != bounds.x() &&
        bounds_.y() != bounds.y() &&
        bounds_.width() != bounds.width() &&
        bounds_.height() != bounds.height()) {
      cache_->RemoveObserver(this);
      base::MessageLoopForUI::current()->Quit();
    }
  }

 private:
  ShellWindowGeometryCache* cache_;
  std::string extension_id_;
  std::string window_id_;
  gfx::Rect bounds_;
};

// Helper class for tests related to the Apps Window API (chrome.app.window).
class AppWindowAPI : public extensions::PlatformAppBrowserTest {
 public:
  bool RunAppWindowAPITest(const char* testName) {
    ExtensionTestMessageListener launched_listener("Launched", true);
    LoadAndLaunchPlatformApp("window_api");
    if (!launched_listener.WaitUntilSatisfied()) {
      message_ = "Did not get the 'Launched' message.";
      return false;
    }

    ResultCatcher catcher;
    launched_listener.Reply(testName);

    if (!catcher.GetNextResult()) {
      message_ = catcher.message();
      return false;
    }

    return true;
  }
};

// These tests are flaky after https://codereview.chromium.org/57433010/.
// See http://crbug.com/319613.

IN_PROC_BROWSER_TEST_F(AppWindowAPI, DISABLED_TestCreate) {
  ASSERT_TRUE(RunAppWindowAPITest("testCreate")) << message_;
}

IN_PROC_BROWSER_TEST_F(AppWindowAPI, DISABLED_TestSingleton) {
  ASSERT_TRUE(RunAppWindowAPITest("testSingleton")) << message_;
}

IN_PROC_BROWSER_TEST_F(AppWindowAPI, DISABLED_TestBounds) {
  ASSERT_TRUE(RunAppWindowAPITest("testBounds")) << message_;
}

IN_PROC_BROWSER_TEST_F(AppWindowAPI, DISABLED_TestCloseEvent) {
  ASSERT_TRUE(RunAppWindowAPITest("testCloseEvent")) << message_;
}

IN_PROC_BROWSER_TEST_F(AppWindowAPI, DISABLED_TestMaximize) {
  ASSERT_TRUE(RunAppWindowAPITest("testMaximize")) << message_;
}

IN_PROC_BROWSER_TEST_F(AppWindowAPI, DISABLED_TestRestore) {
  ASSERT_TRUE(RunAppWindowAPITest("testRestore")) << message_;
}

IN_PROC_BROWSER_TEST_F(AppWindowAPI, DISABLED_TestRestoreAfterClose) {
  ASSERT_TRUE(RunAppWindowAPITest("testRestoreAfterClose")) << message_;
}

// Flaky failures on mac_rel and WinXP, see http://crbug.com/324915.
IN_PROC_BROWSER_TEST_F(AppWindowAPI, DISABLED_TestRestoreGeometryCacheChange) {
  // This test is similar to the other AppWindowAPI tests except that at some
  // point the app will send a 'ListenGeometryChange' message at which point the
  // test will check if the geometry cache entry for the test window has
  // changed. When the change happens, the test will let the app know so it can
  // continue running.
  ExtensionTestMessageListener launched_listener("Launched", true);

  content::WindowedNotificationObserver app_loaded_observer(
      content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
      content::NotificationService::AllSources());

  const extensions::Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("platform_apps").AppendASCII("window_api"));
  EXPECT_TRUE(extension);

  OpenApplication(AppLaunchParams(browser()->profile(),
                                  extension,
                                  extensions::LAUNCH_CONTAINER_NONE,
                                  NEW_WINDOW));

  ExtensionTestMessageListener geometry_listener("ListenGeometryChange", true);

  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
  launched_listener.Reply("testRestoreAfterGeometryCacheChange");

  ASSERT_TRUE(geometry_listener.WaitUntilSatisfied());

  GeometryCacheChangeHelper geo_change_helper(
      ShellWindowGeometryCache::Get(browser()->profile()), extension->id(),
      // The next line has information that has to stay in sync with the app.
      "test-ps", gfx::Rect(200, 200, 200, 200));

  // This call will block until the shell window geometry cache will be changed.
  geo_change_helper.WaitForEntirelyChanged();

  ResultCatcher catcher;
  geometry_listener.Reply("");
  ASSERT_TRUE(catcher.GetNextResult());
}

IN_PROC_BROWSER_TEST_F(AppWindowAPI, DISABLED_TestSizeConstraints) {
  ASSERT_TRUE(RunAppWindowAPITest("testSizeConstraints")) << message_;
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/cros/login_library.h"

#include "base/message_loop.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/chromeos/cros/cros_library.h"

namespace chromeos {

class LoginLibraryImpl : public LoginLibrary {
 public:
  LoginLibraryImpl()
      : set_owner_key_callback_(NULL),
        whitelist_op_callback_(NULL),
        property_op_callback_(NULL) {
    if (CrosLibrary::Get()->EnsureLoaded())
      Init();
  }
  virtual ~LoginLibraryImpl() {
    if (session_connection_) {
      chromeos::DisconnectSession(session_connection_);
    }
  }

  bool EmitLoginPromptReady() {
    return chromeos::EmitLoginPromptReady();
  }

  bool CheckWhitelist(const std::string& email,
                      std::vector<uint8>* OUT_signature) {
    return chromeos::CheckWhitelist(email.c_str(), OUT_signature);
  }

  bool RetrieveProperty(const std::string& name,
                        std::string* OUT_value,
                        std::vector<uint8>* OUT_signature) {
    return chromeos::RetrieveProperty(name.c_str(), OUT_value, OUT_signature);
  }

  bool SetOwnerKeyAsync(const std::vector<uint8>& public_key_der,
                        Delegate* callback) {
    DCHECK(callback) << "must provide a callback to SetOwnerKeyAsync()";
    if (set_owner_key_callback_)
      return false;
    set_owner_key_callback_ =  callback;
    return chromeos::SetOwnerKey(public_key_der);
  }

  bool StorePropertyAsync(const std::string& name,
                          const std::string& value,
                          const std::vector<uint8>& signature,
                          Delegate* callback) {
    DCHECK(callback) << "must provide a callback to StorePropertyAsync()";
    if (property_op_callback_)
      return false;
    property_op_callback_ = callback;
    return chromeos::StoreProperty(name.c_str(), value.c_str(), signature);
  }

  bool UnwhitelistAsync(const std::string& email,
                        const std::vector<uint8>& signature,
                        Delegate* callback) {
    DCHECK(callback) << "must provide a callback to UnwhitelistAsync()";
    if (whitelist_op_callback_)
      return false;
    whitelist_op_callback_ =  callback;
    return chromeos::Unwhitelist(email.c_str(), signature);
  }

  bool WhitelistAsync(const std::string& email,
                      const std::vector<uint8>& signature,
                      Delegate* callback) {
    DCHECK(callback) << "must provide a callback to WhitelistAsync()";
    if (whitelist_op_callback_)
      return false;
    whitelist_op_callback_ =  callback;
    return chromeos::Whitelist(email.c_str(), signature);
  }

  bool EnumerateWhitelisted(std::vector<std::string>* whitelisted) {
    return chromeos::EnumerateWhitelisted(whitelisted);
  }

  bool StartSession(const std::string& user_email,
                    const std::string& unique_id /* unused */) {
    // only pass unique_id through once we use it for something.
    return chromeos::StartSession(user_email.c_str(), "");
  }

  bool StopSession(const std::string& unique_id /* unused */) {
    // only pass unique_id through once we use it for something.
    return chromeos::StopSession("");
  }

  bool RestartJob(int pid, const std::string& command_line) {
    return chromeos::RestartJob(pid, command_line.c_str());
  }

 private:
  static void Handler(void* object, const OwnershipEvent& event) {
    LoginLibraryImpl* self = static_cast<LoginLibraryImpl*>(object);
    switch (event) {
      case SetKeySuccess:
        self->CompleteSetOwnerKey(true);
        break;
      case SetKeyFailure:
        self->CompleteSetOwnerKey(false);
        break;
      case WhitelistOpSuccess:
        self->CompleteWhitelistOp(true);
        break;
      case WhitelistOpFailure:
        self->CompleteWhitelistOp(false);
        break;
      case PropertyOpSuccess:
        self->CompletePropertyOp(true);
        break;
      case PropertyOpFailure:
        self->CompletePropertyOp(false);
        break;
      default:
        NOTREACHED();
        break;
    }
  }

  void Init() {
    session_connection_ = chromeos::MonitorSession(&Handler, this);
  }

  void CompleteSetOwnerKey(bool result) {
    if (set_owner_key_callback_) {
      set_owner_key_callback_->OnComplete(result);
      set_owner_key_callback_ = NULL;
    }
  }

  void CompleteWhitelistOp(bool result) {
    if (whitelist_op_callback_) {
      whitelist_op_callback_->OnComplete(result);
      whitelist_op_callback_ = NULL;
    }
  }

  void CompletePropertyOp(bool result) {
    if (property_op_callback_) {
      property_op_callback_->OnComplete(result);
      property_op_callback_ = NULL;
    }
  }

  chromeos::SessionConnection session_connection_;

  Delegate* set_owner_key_callback_;
  Delegate* whitelist_op_callback_;
  Delegate* property_op_callback_;

  DISALLOW_COPY_AND_ASSIGN(LoginLibraryImpl);
};

class LoginLibraryStubImpl : public LoginLibrary {
 public:
  LoginLibraryStubImpl() {}
  virtual ~LoginLibraryStubImpl() {}

  bool EmitLoginPromptReady() { return true; }
  bool CheckWhitelist(const std::string& email,
                      std::vector<uint8>* OUT_signature) {
    OUT_signature->assign(2, 0);
    return true;
  }
  bool RetrieveProperty(const std::string& name,
                        std::string* OUT_value,
                        std::vector<uint8>* OUT_signature) {
    OUT_value->assign("stub");
    OUT_signature->assign(2, 0);
    return true;
  }
  bool SetOwnerKeyAsync(const std::vector<uint8>& public_key_der,
                        Delegate* callback) {
    BrowserThread::PostTask(
        BrowserThread::UI, FROM_HERE,
        NewRunnableFunction(&DoStubCallback, callback));
    return true;
  }
  bool StorePropertyAsync(const std::string& name,
                          const std::string& value,
                          const std::vector<uint8>& signature,
                          Delegate* callback) {
    BrowserThread::PostTask(
        BrowserThread::UI, FROM_HERE,
        NewRunnableFunction(&DoStubCallback, callback));
    return true;
  }
  bool UnwhitelistAsync(const std::string& email,
                        const std::vector<uint8>& signature,
                        Delegate* callback) {
    BrowserThread::PostTask(
        BrowserThread::UI, FROM_HERE,
        NewRunnableFunction(&DoStubCallback, callback));
    return true;
  }
  bool WhitelistAsync(const std::string& email,
                      const std::vector<uint8>& signature,
                      Delegate* callback) {
    BrowserThread::PostTask(
        BrowserThread::UI, FROM_HERE,
        NewRunnableFunction(&DoStubCallback, callback));
    return true;
  }
  bool EnumerateWhitelisted(std::vector<std::string>* whitelisted) {
    return true;
  }
  bool StartSession(const std::string& user_email,
                    const std::string& unique_id /* unused */) { return true; }
  bool StopSession(const std::string& unique_id /* unused */) { return true; }
  bool RestartJob(int pid, const std::string& command_line) { return true; }

 private:
  static void DoStubCallback(Delegate* callback) {
    callback->OnComplete(true);
  }

  DISALLOW_COPY_AND_ASSIGN(LoginLibraryStubImpl);
};

// static
LoginLibrary* LoginLibrary::GetImpl(bool stub) {
  if (stub)
    return new LoginLibraryStubImpl();
  else
    return new LoginLibraryImpl();
}

}  // namespace chromeos
<commit_msg>[cros] migrate to safe ownership API<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/cros/login_library.h"

#include "base/message_loop.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/chromeos/cros/cros_library.h"

namespace chromeos {

class LoginLibraryImpl : public LoginLibrary {
 public:
  LoginLibraryImpl()
      : set_owner_key_callback_(NULL),
        whitelist_op_callback_(NULL),
        property_op_callback_(NULL) {
    if (CrosLibrary::Get()->EnsureLoaded())
      Init();
  }
  virtual ~LoginLibraryImpl() {
    if (session_connection_) {
      chromeos::DisconnectSession(session_connection_);
    }
  }

  bool EmitLoginPromptReady() {
    return chromeos::EmitLoginPromptReady();
  }

  bool CheckWhitelist(const std::string& email,
                      std::vector<uint8>* OUT_signature) {
    CryptoBlob* sig = NULL;
    if (chromeos::CheckWhitelistSafe(email.c_str(), &sig)) {
      OUT_signature->assign(sig->data, sig->data + sig->length);
      chromeos::FreeCryptoBlob(sig);
      return true;
    }
    return false;
  }

  bool RetrieveProperty(const std::string& name,
                        std::string* OUT_value,
                        std::vector<uint8>* OUT_signature) {
    Property* prop = NULL;
    if (chromeos::RetrievePropertySafe(name.c_str(), &prop)) {
      OUT_value->assign(prop->value);
      CryptoBlob* sig = prop->signature;
      OUT_signature->assign(sig->data, sig->data + sig->length);
      chromeos::FreeProperty(prop);
      return true;
    }
    return false;
  }

  bool SetOwnerKeyAsync(const std::vector<uint8>& public_key_der,
                        Delegate* callback) {
    DCHECK(callback) << "must provide a callback to SetOwnerKeyAsync()";
    if (set_owner_key_callback_)
      return false;
    set_owner_key_callback_ =  callback;
    CryptoBlob* key = chromeos::CreateCryptoBlob(&public_key_der[0],
                                                 public_key_der.size());
    bool rv = chromeos::SetOwnerKeySafe(key);
    chromeos::FreeCryptoBlob(key);
    return rv;
  }

  bool StorePropertyAsync(const std::string& name,
                          const std::string& value,
                          const std::vector<uint8>& signature,
                          Delegate* callback) {
    DCHECK(callback) << "must provide a callback to StorePropertyAsync()";
    if (property_op_callback_)
      return false;
    property_op_callback_ = callback;
    Property* prop = chromeos::CreateProperty(name.c_str(),
                                              value.c_str(),
                                              &signature[0],
                                              signature.size());
    bool rv = chromeos::StorePropertySafe(prop);
    chromeos::FreeProperty(prop);
    return rv;
  }

  bool UnwhitelistAsync(const std::string& email,
                        const std::vector<uint8>& signature,
                        Delegate* callback) {
    DCHECK(callback) << "must provide a callback to UnwhitelistAsync()";
    if (whitelist_op_callback_)
      return false;
    whitelist_op_callback_ =  callback;
    CryptoBlob* sig = chromeos::CreateCryptoBlob(&signature[0],
                                                 signature.size());
    bool rv = chromeos::UnwhitelistSafe(email.c_str(), sig);
    chromeos::FreeCryptoBlob(sig);
    return rv;
  }

  bool WhitelistAsync(const std::string& email,
                      const std::vector<uint8>& signature,
                      Delegate* callback) {
    DCHECK(callback) << "must provide a callback to WhitelistAsync()";
    if (whitelist_op_callback_)
      return false;
    whitelist_op_callback_ =  callback;
    CryptoBlob* sig = chromeos::CreateCryptoBlob(&signature[0],
                                                 signature.size());
    bool rv = chromeos::WhitelistSafe(email.c_str(), sig);
    chromeos::FreeCryptoBlob(sig);
    return rv;
  }

  bool EnumerateWhitelisted(std::vector<std::string>* whitelisted) {
    UserList* list = NULL;
    if (chromeos::EnumerateWhitelistedSafe(&list)) {
      for (int i = 0; i < list->num_users; i++)
        whitelisted->push_back(std::string(list->users[i]));
      chromeos::FreeUserList(list);
      return true;
    }
    return false;
  }

  bool StartSession(const std::string& user_email,
                    const std::string& unique_id /* unused */) {
    // only pass unique_id through once we use it for something.
    return chromeos::StartSession(user_email.c_str(), "");
  }

  bool StopSession(const std::string& unique_id /* unused */) {
    // only pass unique_id through once we use it for something.
    return chromeos::StopSession("");
  }

  bool RestartJob(int pid, const std::string& command_line) {
    return chromeos::RestartJob(pid, command_line.c_str());
  }

 private:
  static void Handler(void* object, const OwnershipEvent& event) {
    LoginLibraryImpl* self = static_cast<LoginLibraryImpl*>(object);
    switch (event) {
      case SetKeySuccess:
        self->CompleteSetOwnerKey(true);
        break;
      case SetKeyFailure:
        self->CompleteSetOwnerKey(false);
        break;
      case WhitelistOpSuccess:
        self->CompleteWhitelistOp(true);
        break;
      case WhitelistOpFailure:
        self->CompleteWhitelistOp(false);
        break;
      case PropertyOpSuccess:
        self->CompletePropertyOp(true);
        break;
      case PropertyOpFailure:
        self->CompletePropertyOp(false);
        break;
      default:
        NOTREACHED();
        break;
    }
  }

  void Init() {
    session_connection_ = chromeos::MonitorSession(&Handler, this);
  }

  void CompleteSetOwnerKey(bool result) {
    if (set_owner_key_callback_) {
      set_owner_key_callback_->OnComplete(result);
      set_owner_key_callback_ = NULL;
    }
  }

  void CompleteWhitelistOp(bool result) {
    if (whitelist_op_callback_) {
      whitelist_op_callback_->OnComplete(result);
      whitelist_op_callback_ = NULL;
    }
  }

  void CompletePropertyOp(bool result) {
    if (property_op_callback_) {
      property_op_callback_->OnComplete(result);
      property_op_callback_ = NULL;
    }
  }

  chromeos::SessionConnection session_connection_;

  Delegate* set_owner_key_callback_;
  Delegate* whitelist_op_callback_;
  Delegate* property_op_callback_;

  DISALLOW_COPY_AND_ASSIGN(LoginLibraryImpl);
};

class LoginLibraryStubImpl : public LoginLibrary {
 public:
  LoginLibraryStubImpl() {}
  virtual ~LoginLibraryStubImpl() {}

  bool EmitLoginPromptReady() { return true; }
  bool CheckWhitelist(const std::string& email,
                      std::vector<uint8>* OUT_signature) {
    OUT_signature->assign(2, 0);
    return true;
  }
  bool RetrieveProperty(const std::string& name,
                        std::string* OUT_value,
                        std::vector<uint8>* OUT_signature) {
    OUT_value->assign("stub");
    OUT_signature->assign(2, 0);
    return true;
  }
  bool SetOwnerKeyAsync(const std::vector<uint8>& public_key_der,
                        Delegate* callback) {
    BrowserThread::PostTask(
        BrowserThread::UI, FROM_HERE,
        NewRunnableFunction(&DoStubCallback, callback));
    return true;
  }
  bool StorePropertyAsync(const std::string& name,
                          const std::string& value,
                          const std::vector<uint8>& signature,
                          Delegate* callback) {
    BrowserThread::PostTask(
        BrowserThread::UI, FROM_HERE,
        NewRunnableFunction(&DoStubCallback, callback));
    return true;
  }
  bool UnwhitelistAsync(const std::string& email,
                        const std::vector<uint8>& signature,
                        Delegate* callback) {
    BrowserThread::PostTask(
        BrowserThread::UI, FROM_HERE,
        NewRunnableFunction(&DoStubCallback, callback));
    return true;
  }
  bool WhitelistAsync(const std::string& email,
                      const std::vector<uint8>& signature,
                      Delegate* callback) {
    BrowserThread::PostTask(
        BrowserThread::UI, FROM_HERE,
        NewRunnableFunction(&DoStubCallback, callback));
    return true;
  }
  bool EnumerateWhitelisted(std::vector<std::string>* whitelisted) {
    return true;
  }
  bool StartSession(const std::string& user_email,
                    const std::string& unique_id /* unused */) { return true; }
  bool StopSession(const std::string& unique_id /* unused */) { return true; }
  bool RestartJob(int pid, const std::string& command_line) { return true; }

 private:
  static void DoStubCallback(Delegate* callback) {
    callback->OnComplete(true);
  }

  DISALLOW_COPY_AND_ASSIGN(LoginLibraryStubImpl);
};

// static
LoginLibrary* LoginLibrary::GetImpl(bool stub) {
  if (stub)
    return new LoginLibraryStubImpl();
  else
    return new LoginLibraryImpl();
}

}  // namespace chromeos
<|endoftext|>