<commit_before>/*

Copyright (c) 2010, Arvid Norberg
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 author 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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 "libtorrent/storage.hpp"
#include "libtorrent/file_pool.hpp"

#include <boost/utility.hpp>

#include <stdlib.h>

using namespace libtorrent;

int main(int argc, char* argv[])
{
	if (argc != 3 && argc != 2)
	{
		fprintf(stderr, "Usage: fragmentation_test torrent-file file-storage-path\n"
			"       fragmentation_test file\n\n");
		return 1;
	}

	if (argc == 2)
	{
		error_code ec;
		file f(argv[1], file::read_only, ec);
		if (ec)
		{
			fprintf(stderr, "Error opening file %s: %s\n", argv[1], ec.message().c_str());
			return 1;
		}
		size_type off = f.phys_offset(0);
		printf("physical offset of file %s: %" PRId64 "\n", argv[1], off);
		return 0;
	}

	error_code ec;
	boost::intrusive_ptr<torrent_info> ti(new torrent_info(argv[1], ec));

	if (ec)
	{
		fprintf(stderr, "Error while loading torrent file: %s\n", ec.message().c_str());
		return 1;
	}

	file_pool fp;
	boost::shared_ptr<storage_interface> st(default_storage_constructor(ti->files(), 0, argv[2], fp, std::vector<boost::uint8_t>()));

	// the first field is the piece index, the second
	// one is the physical location of the piece on disk
	std::vector<std::pair<int, size_type> > pieces;

	// make sure all the files are there
	std::vector<std::pair<size_type, std::time_t> > files = get_filesizes(ti->files(), argv[2]);
	for (int i = 0; i < ti->num_files(); ++i)
	{
		if (ti->file_at(i).size == files[i].first) continue;
		fprintf(stderr, "Files for this torrent are missing or incomplete: %s was %"PRId64" bytes, expected %"PRId64" bytes\n"
			, ti->files().file_path(ti->file_at(i)).c_str(), files[i].first, ti->file_at(i).size);
		return 1;
	}

	for (int i = 0; i < ti->num_pieces(); ++i)
	{
		pieces.push_back(std::make_pair(i, st->physical_offset(i, 0)));
		if (pieces.back().second == size_type(i) * ti->piece_length())
		{
			// this suggests that the OS doesn't support physical offset
			// or that the file doesn't exist, or some other file error
			fprintf(stderr, "Your operating system or filesystem "
				"does not appear to support querying physical disk offset\n");
			return 1;
		}
	}

	FILE* f = fopen("fragmentation.log", "w+");
	if (f == 0)
	{
		fprintf(stderr, "error while opening log file: %s\n", strerror(errno));
		return 1;
	}

	for (int i = 0; i < ti->num_pieces(); ++i)
	{
		fprintf(f, "%d %"PRId64"\n", pieces[i].first, pieces[i].second);
	}

	fclose(f);

	f = fopen("fragmentation.gnuplot", "w+");
	if (f == 0)
	{
		fprintf(stderr, "error while opening gnuplot file: %s\n", strerror(errno));
		return 1;
	}

	fprintf(f,
		"set term png size 1200,800\n"
		"set output \"fragmentation.png\"\n"
		"set xrange [*:*]\n"
		"set xlabel \"piece\"\n"
		"set ylabel \"drive offset\"\n"
		"set key box\n"
		"set title \"fragmentation for '%s'\"\n"
		"set tics nomirror\n"
		"plot \"fragmentation.log\" using 1:2 with dots lt rgb \"#e07070\" notitle axis x1y1\n"
		, ti->name().c_str());

	fclose(f);

	system("gnuplot fragmentation.gnuplot");
}

<commit_msg>make fragmentation_test work with incomplete files as well<commit_after>/*

Copyright (c) 2010, Arvid Norberg
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 author 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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 "libtorrent/storage.hpp"
#include "libtorrent/file_pool.hpp"

#include <boost/utility.hpp>

#include <stdlib.h>

using namespace libtorrent;

int main(int argc, char* argv[])
{
	if (argc != 3 && argc != 2)
	{
		fprintf(stderr, "Usage: fragmentation_test torrent-file file-storage-path\n"
			"       fragmentation_test file\n\n");
		return 1;
	}

	if (argc == 2)
	{
		error_code ec;
		file f(argv[1], file::read_only, ec);
		if (ec)
		{
			fprintf(stderr, "Error opening file %s: %s\n", argv[1], ec.message().c_str());
			return 1;
		}
		size_type off = f.phys_offset(0);
		printf("physical offset of file %s: %" PRId64 "\n", argv[1], off);
		return 0;
	}

	error_code ec;
	boost::intrusive_ptr<torrent_info> ti(new torrent_info(argv[1], ec));

	if (ec)
	{
		fprintf(stderr, "Error while loading torrent file: %s\n", ec.message().c_str());
		return 1;
	}

	file_pool fp;
	boost::shared_ptr<storage_interface> st(default_storage_constructor(ti->files(), 0, argv[2], fp, std::vector<boost::uint8_t>()));

	// the first field is the piece index, the second
	// one is the physical location of the piece on disk
	std::vector<std::pair<int, size_type> > pieces;

	// make sure all the files are there
/*	std::vector<std::pair<size_type, std::time_t> > files = get_filesizes(ti->files(), argv[2]);
	for (int i = 0; i < ti->num_files(); ++i)
	{
		if (ti->file_at(i).size == files[i].first) continue;
		fprintf(stderr, "Files for this torrent are missing or incomplete: %s was %"PRId64" bytes, expected %"PRId64" bytes\n"
			, ti->files().file_path(ti->file_at(i)).c_str(), files[i].first, ti->file_at(i).size);
		return 1;
	}
*/
	bool warned = false;
	for (int i = 0; i < ti->num_pieces(); ++i)
	{
		pieces.push_back(std::make_pair(i, st->physical_offset(i, 0)));
		if (pieces.back().second == size_type(i) * ti->piece_length())
		{
			// this suggests that the OS doesn't support physical offset
			// or that the file doesn't exist or is incomplete
			if (!warned)
			{
				fprintf(stderr, "The files are incomplete\n");
				warned = true;
			}
			pieces.pop_back();
		}
	}

	if (pieces.empty())
	{
		fprintf(stderr, "Your operating system or filesystem "
			"does not appear to support querying physical disk offset\n");
	}

	FILE* f = fopen("fragmentation.log", "w+");
	if (f == 0)
	{
		fprintf(stderr, "error while opening log file: %s\n", strerror(errno));
		return 1;
	}

	for (int i = 0; i < pieces.size(); ++i)
	{
		fprintf(f, "%d %"PRId64"\n", pieces[i].first, pieces[i].second);
	}

	fclose(f);

	f = fopen("fragmentation.gnuplot", "w+");
	if (f == 0)
	{
		fprintf(stderr, "error while opening gnuplot file: %s\n", strerror(errno));
		return 1;
	}

	fprintf(f,
		"set term png size 1200,800\n"
		"set output \"fragmentation.png\"\n"
		"set xrange [*:*]\n"
		"set xlabel \"piece\"\n"
		"set ylabel \"drive offset\"\n"
		"set key box\n"
		"set title \"fragmentation for '%s'\"\n"
		"set tics nomirror\n"
		"plot \"fragmentation.log\" using 1:2 with points lt rgb \"#e07070\" notitle axis x1y1\n"
		, ti->name().c_str());

	fclose(f);

	system("gnuplot fragmentation.gnuplot");
}

<|endoftext|>


<commit_before>/*    Copyright (c) 2010-2012 Delft University of Technology.
 *
 *    This software is protected by national and international copyright.
 *    Any unauthorized use, reproduction or modification is unlawful and
 *    will be prosecuted. Commercial and non-private application of the
 *    software in any form is strictly prohibited unless otherwise granted
 *    by the authors.
 *
 *    The code is provided without any warranty; without even the implied
 *    warranty of merchantibility or fitness for a particular purpose.
 *
 *    Changelog
 *      YYMMDD    Author            Comment
 *      110405    K. Kumar          File created.
 *      110406    K. Kumar          Added cerr statements.
 *      110411    K. Kumar          Changed test to check errors in position, right ascension, and
 *                                  declination.
 *      110701    K. Kumar          Updated to use new predefined planets architecture; removed
 *                                  dynamic memory allocation.
 *      110714    L. van der Ham    Added circular coplanar case.
 *      111024    K. Kumar          Spotted error in circular coplanar test after changing abs( )
 *                                  to fabs( ). Needs to be fixed.
 *      120322    D. Dirkx          Modified to new Ephemeris interfaces.
 *      120513    P. Musegaas       Boostified unit test.
 *
 *    References
 *      HORIZONS Web-Interface, http://ssd.jpl.nasa.gov/horizons.cgi, last accessed: 5 April, 2011.
 *
 *    It is noted during the 120513 check that this is not a very extensive and/or precise unit
 *    test. Given that the ephemeris class will soon be updated, this is not deemed a big issue.
 *    However the unit test will have to be improved a lot in the next update. Some code was
 *    outcommented when boostifying the unit test. It is attached in commented version at the
 *    bottom of this file.
 *
 *    Also the test of the approximate planet positions (3D) was changed. It used to check the
 *    only the spherical position coordinates. It was changed to check the cartesian elements in
 *    total. The accuracy with which this is possible is very low though.
 */

#define BOOST_TEST_MAIN

#include <boost/test/floating_point_comparison.hpp>
#include <boost/test/unit_test.hpp>

#include <TudatCore/Basics/testMacros.h>
#include <TudatCore/Astrodynamics/BasicAstrodynamics/unitConversions.h>
#include <TudatCore/Astrodynamics/BasicAstrodynamics/orbitalElementConversions.h>

#include "Tudat/Astrodynamics/Bodies/celestialBody.h"
#include "Tudat/Astrodynamics/Bodies/planet.h"
#include "Tudat/Astrodynamics/Bodies/Ephemeris/approximatePlanetPositionsCircularCoplanar.h"

namespace tudat
{
namespace unit_tests
{

//! Test the functionality of the approximate planet position functions
BOOST_AUTO_TEST_SUITE( test_approximate_planet_positions )

//! Test the orbital elements function against the orbital elements of Mars at JD 2455626.5.
BOOST_AUTO_TEST_CASE( testOrbitalElements )
{
    using tudat::unit_conversions::convertDegreesToRadians;

    // Set tolerance.
    const double tolerance = 2.0e-2;

    // Expected result.
    Eigen::VectorXd expectedKeplerianElements( 6 );
    expectedKeplerianElements[ 0 ] = 2.279361944126564e11;
    expectedKeplerianElements[ 1 ] = 9.338126166083623e-2;
    expectedKeplerianElements[ 2 ] = convertDegreesToRadians( 1.848907897011101 );
    expectedKeplerianElements[ 3 ] = convertDegreesToRadians( 2.866464026954701e2 );
    expectedKeplerianElements[ 4 ] = convertDegreesToRadians( 4.952419052428279e1 );
    expectedKeplerianElements[ 5 ] = convertDegreesToRadians( 3.577219707986779e2 );

    // Create predefined Mars.
    bodies::Planet predefinedMars;
    predefinedMars.setPredefinedPlanetSettings( bodies::Planet::mars );

    // Create predefined Sun.
    bodies::Planet predefinedSun;
    predefinedSun.setPredefinedPlanetSettings( bodies::Planet::sun );

    // Convert the expected Keplerian elements to Cartesian elements.
    Eigen::VectorXd expectedEphemeris;
    expectedEphemeris = orbital_element_conversions::convertKeplerianToCartesianElements(
            expectedKeplerianElements,
            predefinedSun.getGravityFieldModel( )->getGravitationalParameter( ) );

    // Retrieve state of Mars in Cartesian elements at Julian date 2455626.5.
    Eigen::VectorXd marsEphemeris;
    marsEphemeris = predefinedMars.getEphemeris( )->getCartesianStateFromEphemeris( 2455626.5 );

    // Test if the computed ephemeris matches the expected ephemeris within the tolerance set.
    TUDAT_CHECK_MATRIX_CLOSE_FRACTION( expectedEphemeris, marsEphemeris, tolerance );
}

//! Test the cicular coplanar function against orbital elements of Mars at JD 2455626.5.
BOOST_AUTO_TEST_CASE( testCircularCoplannar )
{
    using namespace tudat::ephemerides;

    // Create predefined Sun.
    bodies::Planet predefinedSun;
    predefinedSun.setPredefinedPlanetSettings( bodies::Planet::sun );

    // Create predefined Mars and set circular coplanar planet positions.
    bodies::CelestialBody predefinedMarsCircularCoplanar;
    predefinedMarsCircularCoplanar.setEphemeris(
                boost::make_shared< ApproximatePlanetPositionsCircularCoplanar >(
                                             ApproximatePlanetPositionsBase::mars ) );

    Eigen::VectorXd marsEphemerisCircularCoplanar;
    marsEphemerisCircularCoplanar = predefinedMarsCircularCoplanar.getEphemeris( )->
            getCartesianStateFromEphemeris( 2455626.5 );

    // Compute the Keplerian elements from this ephemeris.
    Eigen::VectorXd keplerianElementsCircularCoplanar;
    keplerianElementsCircularCoplanar = orbital_element_conversions::
            convertCartesianToKeplerianElements( marsEphemerisCircularCoplanar,
                    predefinedSun.getGravityFieldModel( )->getGravitationalParameter( ) );

    // Check the eccentricity, inclination and z-component of velocity and position are 0.
    BOOST_CHECK_SMALL( keplerianElementsCircularCoplanar( 1 ),
                       std::numeric_limits< double >::epsilon( ) );
    BOOST_CHECK_SMALL( keplerianElementsCircularCoplanar( 2 ),
                       std::numeric_limits< double >::min( ) );
    BOOST_CHECK_SMALL( marsEphemerisCircularCoplanar( 2 ), 2.0e-5 );
    BOOST_CHECK_SMALL( marsEphemerisCircularCoplanar( 5 ),
                       std::numeric_limits< double >::min( ) );

}

BOOST_AUTO_TEST_SUITE_END( )

} // namespace unit_tests
} // namespace tudat

//    // Compute the difference in semi-major axis between Test 2 and
//    // the external EphemerisData "p_elem_t2.txt".
//    double errorSemiMajorAxis = fabs( positionMars.norm( )
//                                      - convertAstronomicalUnitsToMeters( 1.52371243 ) )
//            / convertAstronomicalUnitsToMeters( 1.52371243 );

//    if ( errorSemiMajorAxis > errorTolerance_ )
//    {
//        isApproximatePlanetPositionsErroneous = true;

//        // Generate error statements.
//        cerr << "The computed relative error in position of the  "<< endl;
//        cerr << "coplanar circular position of Mars ( " << errorSemiMajorAxis << " )"<< endl;
//        cerr << "using the ApproximatePlanetPositionsCircularCoplanar class, exceeds "
//             << "the maximum expected error " << endl;
//        cerr << "( " << errorTolerance_ << " )." << endl;
//    }

//    // Check orientation of position vector by comparison of separate components.
//    // Error in position should be smaller than maximum expected offset with respect to
//    // elliptical and inclined orbits.
//    double maximumErrorPosition =   keplerianElementsTest3D.getSemiMajorAxis( ) * (
//                keplerianElementsTest3D.getEccentricity( ) + 1.0
//                - cos( keplerianElementsTest3D.getInclination( ) ) );
//    Vector3d errorPositionVector = positionMars - marsEphemeris.getPosition( );

//    if ( fabs( errorPositionVector( 0 ) ) > maximumErrorPosition
//         || fabs( errorPositionVector( 1 ) ) > maximumErrorPosition )
//    {
//        isApproximatePlanetPositionsErroneous = true;

//        // Generate error statements.
//        cerr << "The computed error in position vector of the  "<< endl;
//        cerr << "coplanar circular position of Mars ( "
//             << errorPositionVector << " meters )" << endl;
//        cerr << "using the ApproximatePlanetPositionsCircularCoplanar class, exceeds "
//             << "the expected error (" << endl;
//        cerr << "( " << maximumErrorPosition << " meters )." << endl;
//    }

    /* FIX THIS TEST!!!
    // Check size of velocity.
    Eigen::Vector3d errorVelocity = velocityMars - marsEphemeris.segment( 3, 3 );

    // Error in scalar velocity should be smaller than maximum expected offset with respect to
    // ellipitical and inclined orbits.
    double expectedErrorVelocity = fabs(
                sqrt( predefinedSun.getGravitationalParameter( )
                      / marsEphemeris.segment( 0, 3 ).norm( ) ) *
                ( ( 1.0 - cos( keplerianElementsTest3D.getInclination( ) )
                    + sqrt( ( 1.0 - keplerianElementsTest3D.getEccentricity( ) ) /
                            ( 1.0 + keplerianElementsTest3D.getEccentricity( ) ) ) - 1.0 ) ) );

    if ( errorVelocity.norm( ) > expectedErrorVelocity )
    {
        isApproximatePlanetPositionsErroneous = true;

        // Generate error statements.
        cerr << "The computed error in velocity of the "<< endl;
        cerr << "coplanar circular position of Mars "
             << "( " << errorVelocity.norm( ) << " meters per second )" << endl;
        cerr << "using the ApproximatePlanetPositionsCircularCoplanar class, exceeds "
             << "the expected error " << endl;
        cerr << "( " << expectedErrorVelocity << " meters per second )." << endl;
        cerr << "The computed error exceeds the expected error by: "
             << fabs( errorVelocity.norm( ) - expectedErrorVelocity )
             << " meters per second." << endl;
    }
    */
<commit_msg>Fixed bug in approximate planet position unit test (#issue 479).<commit_after>/*    Copyright (c) 2010-2012 Delft University of Technology.
 *
 *    This software is protected by national and international copyright.
 *    Any unauthorized use, reproduction or modification is unlawful and
 *    will be prosecuted. Commercial and non-private application of the
 *    software in any form is strictly prohibited unless otherwise granted
 *    by the authors.
 *
 *    The code is provided without any warranty; without even the implied
 *    warranty of merchantibility or fitness for a particular purpose.
 *
 *    Changelog
 *      YYMMDD    Author            Comment
 *      110405    K. Kumar          File created.
 *      110406    K. Kumar          Added cerr statements.
 *      110411    K. Kumar          Changed test to check errors in position, right ascension, and
 *                                  declination.
 *      110701    K. Kumar          Updated to use new predefined planets architecture; removed
 *                                  dynamic memory allocation.
 *      110714    L. van der Ham    Added circular coplanar case.
 *      111024    K. Kumar          Spotted error in circular coplanar test after changing abs( )
 *                                  to fabs( ). Needs to be fixed.
 *      120322    D. Dirkx          Modified to new Ephemeris interfaces.
 *      120513    P. Musegaas       Boostified unit test.
 *
 *    References
 *      HORIZONS Web-Interface, http://ssd.jpl.nasa.gov/horizons.cgi, last accessed: 5 April, 2011.
 *
 *    It is noted during the 120513 check that this is not a very extensive and/or precise unit
 *    test. Given that the ephemeris class will soon be updated, this is not deemed a big issue.
 *    However the unit test will have to be improved a lot in the next update. Some code was
 *    outcommented when boostifying the unit test. It is attached in commented version at the
 *    bottom of this file.
 *
 *    Also the test of the approximate planet positions (3D) was changed. It used to check the
 *    only the spherical position coordinates. It was changed to check the cartesian elements in
 *    total. The accuracy with which this is possible is very low though.
 */

#define BOOST_TEST_MAIN

#include <boost/test/floating_point_comparison.hpp>
#include <boost/test/unit_test.hpp>

#include <TudatCore/Basics/testMacros.h>
#include <TudatCore/Astrodynamics/BasicAstrodynamics/unitConversions.h>
#include <TudatCore/Astrodynamics/BasicAstrodynamics/orbitalElementConversions.h>

#include "Tudat/Astrodynamics/Bodies/celestialBody.h"
#include "Tudat/Astrodynamics/Bodies/planet.h"
#include "Tudat/Astrodynamics/Bodies/Ephemeris/approximatePlanetPositionsCircularCoplanar.h"

namespace tudat
{
namespace unit_tests
{

//! Test the functionality of the approximate planet position functions
BOOST_AUTO_TEST_SUITE( test_approximate_planet_positions )

//! Test the orbital elements function against the orbital elements of Mars at JD 2455626.5.
BOOST_AUTO_TEST_CASE( testOrbitalElements )
{
    using tudat::unit_conversions::convertDegreesToRadians;

    // Set tolerance.
    const double tolerance = 2.0e-2;

    // Expected result.
    Eigen::VectorXd expectedKeplerianElements( 6 );
    expectedKeplerianElements[ 0 ] = 2.279361944126564e11;
    expectedKeplerianElements[ 1 ] = 9.338126166083623e-2;
    expectedKeplerianElements[ 2 ] = convertDegreesToRadians( 1.848907897011101 );
    expectedKeplerianElements[ 3 ] = convertDegreesToRadians( 2.866464026954701e2 );
    expectedKeplerianElements[ 4 ] = convertDegreesToRadians( 4.952419052428279e1 );
    expectedKeplerianElements[ 5 ] = convertDegreesToRadians( 3.577219707986779e2 );

    // Create predefined Mars.
    bodies::Planet predefinedMars;
    predefinedMars.setPredefinedPlanetSettings( bodies::Planet::mars );

    // Create predefined Sun.
    bodies::Planet predefinedSun;
    predefinedSun.setPredefinedPlanetSettings( bodies::Planet::sun );

    // Convert the expected Keplerian elements to Cartesian elements.
    Eigen::VectorXd expectedEphemeris;
    expectedEphemeris = orbital_element_conversions::convertKeplerianToCartesianElements(
            expectedKeplerianElements,
            predefinedSun.getGravityFieldModel( )->getGravitationalParameter( ) );

    // Retrieve state of Mars in Cartesian elements at Julian date 2455626.5.
    Eigen::VectorXd marsEphemeris;
    marsEphemeris = predefinedMars.getEphemeris( )->getCartesianStateFromEphemeris( 2455626.5 );

    // Test if the computed ephemeris matches the expected ephemeris within the tolerance set.
    TUDAT_CHECK_MATRIX_CLOSE_FRACTION( expectedEphemeris, marsEphemeris, tolerance );
}

//! Test the cicular coplanar function against orbital elements of Mars at JD 2455626.5.
BOOST_AUTO_TEST_CASE( testCircularCoplannar )
{
    using namespace tudat::ephemerides;

    // Create predefined Sun.
    bodies::Planet predefinedSun;
    predefinedSun.setPredefinedPlanetSettings( bodies::Planet::sun );

    // Create predefined Mars and set circular coplanar planet positions.
    bodies::CelestialBody predefinedMarsCircularCoplanar;
    predefinedMarsCircularCoplanar.setEphemeris(
                boost::make_shared< ApproximatePlanetPositionsCircularCoplanar >(
                                             ApproximatePlanetPositionsBase::mars ) );

    Eigen::VectorXd marsEphemerisCircularCoplanar;
    marsEphemerisCircularCoplanar = predefinedMarsCircularCoplanar.getEphemeris( )->
            getCartesianStateFromEphemeris( 2455626.5 );

    // Compute the Keplerian elements from this ephemeris.
    Eigen::VectorXd keplerianElementsCircularCoplanar;
    keplerianElementsCircularCoplanar = orbital_element_conversions::
            convertCartesianToKeplerianElements( marsEphemerisCircularCoplanar,
                    predefinedSun.getGravityFieldModel( )->getGravitationalParameter( ) );

    // Check the eccentricity, inclination and z-component of velocity and position are 0.
    BOOST_CHECK_SMALL( keplerianElementsCircularCoplanar( 1 ), 1e-15 );
    BOOST_CHECK_SMALL( keplerianElementsCircularCoplanar( 2 ),
                       std::numeric_limits< double >::min( ) );
    BOOST_CHECK_SMALL( marsEphemerisCircularCoplanar( 2 ), 2.0e-5 );
    BOOST_CHECK_SMALL( marsEphemerisCircularCoplanar( 5 ),
                       std::numeric_limits< double >::min( ) );

}

BOOST_AUTO_TEST_SUITE_END( )

} // namespace unit_tests
} // namespace tudat

//    // Compute the difference in semi-major axis between Test 2 and
//    // the external EphemerisData "p_elem_t2.txt".
//    double errorSemiMajorAxis = fabs( positionMars.norm( )
//                                      - convertAstronomicalUnitsToMeters( 1.52371243 ) )
//            / convertAstronomicalUnitsToMeters( 1.52371243 );

//    if ( errorSemiMajorAxis > errorTolerance_ )
//    {
//        isApproximatePlanetPositionsErroneous = true;

//        // Generate error statements.
//        cerr << "The computed relative error in position of the  "<< endl;
//        cerr << "coplanar circular position of Mars ( " << errorSemiMajorAxis << " )"<< endl;
//        cerr << "using the ApproximatePlanetPositionsCircularCoplanar class, exceeds "
//             << "the maximum expected error " << endl;
//        cerr << "( " << errorTolerance_ << " )." << endl;
//    }

//    // Check orientation of position vector by comparison of separate components.
//    // Error in position should be smaller than maximum expected offset with respect to
//    // elliptical and inclined orbits.
//    double maximumErrorPosition =   keplerianElementsTest3D.getSemiMajorAxis( ) * (
//                keplerianElementsTest3D.getEccentricity( ) + 1.0
//                - cos( keplerianElementsTest3D.getInclination( ) ) );
//    Vector3d errorPositionVector = positionMars - marsEphemeris.getPosition( );

//    if ( fabs( errorPositionVector( 0 ) ) > maximumErrorPosition
//         || fabs( errorPositionVector( 1 ) ) > maximumErrorPosition )
//    {
//        isApproximatePlanetPositionsErroneous = true;

//        // Generate error statements.
//        cerr << "The computed error in position vector of the  "<< endl;
//        cerr << "coplanar circular position of Mars ( "
//             << errorPositionVector << " meters )" << endl;
//        cerr << "using the ApproximatePlanetPositionsCircularCoplanar class, exceeds "
//             << "the expected error (" << endl;
//        cerr << "( " << maximumErrorPosition << " meters )." << endl;
//    }

    /* FIX THIS TEST!!!
    // Check size of velocity.
    Eigen::Vector3d errorVelocity = velocityMars - marsEphemeris.segment( 3, 3 );

    // Error in scalar velocity should be smaller than maximum expected offset with respect to
    // ellipitical and inclined orbits.
    double expectedErrorVelocity = fabs(
                sqrt( predefinedSun.getGravitationalParameter( )
                      / marsEphemeris.segment( 0, 3 ).norm( ) ) *
                ( ( 1.0 - cos( keplerianElementsTest3D.getInclination( ) )
                    + sqrt( ( 1.0 - keplerianElementsTest3D.getEccentricity( ) ) /
                            ( 1.0 + keplerianElementsTest3D.getEccentricity( ) ) ) - 1.0 ) ) );

    if ( errorVelocity.norm( ) > expectedErrorVelocity )
    {
        isApproximatePlanetPositionsErroneous = true;

        // Generate error statements.
        cerr << "The computed error in velocity of the "<< endl;
        cerr << "coplanar circular position of Mars "
             << "( " << errorVelocity.norm( ) << " meters per second )" << endl;
        cerr << "using the ApproximatePlanetPositionsCircularCoplanar class, exceeds "
             << "the expected error " << endl;
        cerr << "( " << expectedErrorVelocity << " meters per second )." << endl;
        cerr << "The computed error exceeds the expected error by: "
             << fabs( errorVelocity.norm( ) - expectedErrorVelocity )
             << " meters per second." << endl;
    }
    */
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	I2C テンプレートクラス (20MHz system clock) @n
			Copyright 2015 Kunihito Hiramatsu
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <cstdint>
#include "common/delay.hpp"

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  I2C テンプレートクラス @n
				PORT ポート指定クラス： @n
				class port { @n
				public: @n
					void scl_dir(bool val) const { } @n
					void scl_out(bool val) const { } @n
					bool scl_inp() const { return 0; } @n
					void sda_dir(bool val) const { } @n
					void sda_out(bool val) const { } @n
					bool sda_inp() const { return 0; } @n
				};
		@param[in]	PORT	ポート定義クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class PORT>
	class i2c_io {
		PORT		port_;
		uint8_t		clock_;
		uint16_t	busy_;

		static const uint8_t slow_clock_ = 10 / 2;
		static const uint8_t fast_clock_ = 4 / 2;

		void start_() const {
			port_.sda_out(0);
			utils::delay::micro_second(clock_);
			port_.scl_out(0);
			utils::delay::micro_second(clock_);
		}

		bool ack_() const {
			port_.sda_out(1);
			utils::delay::micro_second(clock_);
			port_.scl_out(1);
			port_.sda_dir(0);
			utils::delay::micro_second(clock_);
			bool f = port_.sda_inp();
			port_.sda_dir(1);
			port_.scl_out(0);
			return f;
		}

		void out_ack_(bool b) const {
			utils::delay::micro_second(clock_);
			port_.sda_out(b);
			port_.scl_out(1);
			utils::delay::micro_second(clock_);
			port_.scl_out(0);
		}

		bool wait_() const {
			uint16_t cnt = busy_;
			port_.scl_dir(0);
			while(port_.scl_inp() == 0) {
				utils::delay::micro_second(1);
				if(cnt) {
					--cnt;
				} else {
					port_.scl_dir(1);
					return false;  // wait stall
				}
			}
			port_.scl_dir(1);
			return true;
		}

		void stop_() const {
			utils::delay::micro_second(clock_);
			port_.scl_out(1);
			utils::delay::micro_second(clock_);
			port_.sda_out(1);
		}

		bool write_(uint8_t val, bool sync) const {
			for(uint8_t n = 0; n < 8; ++n) {
				if(val & 0x80) port_.sda_out(1); else port_.sda_out(0);
				utils::delay::micro_second(clock_);
				port_.scl_out(1);
				if(n == 0 && sync) {
					if(!wait_()) return false;
				}
				val <<= 1;
				utils::delay::micro_second(clock_);
				port_.scl_out(0);
			}
			return true;
		}

		bool write_(const uint8_t* src, uint8_t num) const {
			for(uint8_t n = 0; n < num; ++n) {
				if(!write_(*src, true)) {
					stop_();
					return false;
				}
				++src;
				if(ack_()) {
					stop_();
					return false;
				}
			}
			return true;
		}

		bool read_(uint8_t& val, bool sync) const {
			port_.sda_dir(0);
			for(uint8_t n = 0; n < 8; ++n) {
				utils::delay::micro_second(clock_);
				val <<= 1;
				port_.scl_out(1);
				if(n == 0 && sync) {
					if(!wait_()) {
						port_.sda_dir(1);
						return false;
					}
				}
				utils::delay::micro_second(clock_);
				if(port_.sda_inp()) val |= 1;
				port_.scl_out(0);
			}
			port_.sda_dir(1);
			return true;
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		i2c_io() : clock_(slow_clock_), busy_(200) { }

		//-----------------------------------------------------------------//
		/*!
			@brief  初期化
		*/
		//-----------------------------------------------------------------//
		void init() const {
			port_.init();
			port_.scl_dir(1);
			port_.sda_dir(1);
			port_.scl_out(1);
			port_.sda_out(1);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  クロック設定
			@param[in]	clock	パルス５０％待ち時間（単位マイクロ秒）
		*/
		//-----------------------------------------------------------------//
		void set_clock(uint8_t clock) { clock_ = clock; }

		//-----------------------------------------------------------------//
		/*!
			@brief  低速指定（maybe 100KBPS）
		*/
		//-----------------------------------------------------------------//
		void set_slow() { clock_ = slow_clock_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  高速指定（maybe 400KBPS）
		*/
		//-----------------------------------------------------------------//
		void set_fast() { clock_ = fast_clock_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  スレーブデバイスの「待ち」時間の最大値を設定
			@param[in]	busy	待ち時間（単位マイクロ秒）
		*/
		//-----------------------------------------------------------------//
		void set_busy(uint16_t busy) { busy_ = busy; }

		//-----------------------------------------------------------------//
		/*!
			@brief  受信（リード）
			@param[in] address スレーブアドレス（７ビット）
			@param[out]	dst	先
			@param[in]	num	数
			@return 失敗なら「false」が返る
		*/
		//-----------------------------------------------------------------//
		bool recv(uint8_t address, uint8_t* dst, uint8_t num) const {
			start_();
			write_((address << 1) | 1, false);
			if(ack_()) {
				stop_();
				return false;
			}

			for(uint8_t n = 0; n < num; ++n) {
				if(!read_(*dst, true)) {
					stop_();
					return false;
				}
				bool f = 0;
				if(n == (num - 1)) f = 1;
				out_ack_(f);
				++dst;
			}
			stop_();
			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  送信（ライト）
			@param[in] address スレーブアドレス（７ビット）
			@param[in]	src	元
			@param[in]	num	数
			@return 失敗なら「false」が返る
		*/
		//-----------------------------------------------------------------//
		bool send(uint8_t address, const uint8_t* src, uint8_t num) const {
			start_();
			write_(address << 1, false);
			if(ack_()) {
				stop_();
				return false;
			}

			if(!write_(src, num)) {
				stop_();
				return false;
			}
			stop_();
			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  送信（ライト）
			@param[in] address スレーブアドレス（７ビット）
			@param[in]	first	ファーストデータ
			@param[in]	src	元
			@param[in]	num	数
			@return 失敗なら「false」が返る
		*/
		//-----------------------------------------------------------------//
		bool send(uint8_t address, uint8_t first, const uint8_t* src, uint8_t num) const {
			start_();
			write_(address << 1, false);
			if(ack_()) {
				stop_();
				return false;
			}

			if(!write_(first, false)) {
				stop_();
				return false;
			}
			if(ack_()) {
				stop_();
				return false;
			}

			if(!write_(src, num)) {
				stop_();
				return false;
			}
			stop_();
			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  送信（ライト）
			@param[in] address スレーブアドレス（７ビット）
			@param[in]	first	ファースト・データ
			@param[in]	second	セカンド・データ
			@param[in]	src	元
			@param[in]	num	数
			@return 失敗なら「false」が返る
		*/
		//-----------------------------------------------------------------//
		bool send(uint8_t address, uint8_t first, uint8_t second, const uint8_t* src, uint8_t num) const {
			start_();
			write_(address << 1, false);
			if(ack_()) {
				stop_();
				return false;
			}

			if(!write_(first, false)) {
				stop_();
				return false;
			}
			if(ack_()) {
				stop_();
				return false;
			}

			if(!write_(second, false)) {
				stop_();
				return false;
			}
			if(ack_()) {
				stop_();
				return false;
			}

			if(!write_(src, num)) {
				stop_();
				return false;
			}
			stop_();
			return true;
		}
	};
}
<commit_msg>bug fix ack SDA state<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	I2C テンプレートクラス (20MHz system clock) @n
			Copyright 2015 Kunihito Hiramatsu
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <cstdint>
#include "common/delay.hpp"

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  I2C テンプレートクラス @n
				PORT ポート指定クラス： @n
				class port { @n
				public: @n
					void scl_dir(bool val) const { } @n
					void scl_out(bool val) const { } @n
					bool scl_inp() const { return 0; } @n
					void sda_dir(bool val) const { } @n
					void sda_out(bool val) const { } @n
					bool sda_inp() const { return 0; } @n
				};
		@param[in]	PORT	ポート定義クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class PORT>
	class i2c_io {
		PORT		port_;
		uint8_t		clock_;
		uint16_t	busy_;

		static const uint8_t slow_clock_ = 10 / 2;
		static const uint8_t fast_clock_ = 4 / 2;

		void start_() const {
			port_.sda_out(0);
			utils::delay::micro_second(clock_);
			port_.scl_out(0);
			utils::delay::micro_second(clock_);
		}

		bool ack_() const {
			port_.sda_out(1);
			utils::delay::micro_second(clock_);
			port_.scl_out(1);
			port_.sda_dir(0);
			utils::delay::micro_second(clock_);
			bool f = port_.sda_inp();
			port_.sda_out(0);
			port_.sda_dir(1);
			port_.scl_out(0);
			return f;
		}

		void out_ack_(bool b) const {
			utils::delay::micro_second(clock_);
			port_.sda_out(b);
			port_.scl_out(1);
			utils::delay::micro_second(clock_);
			port_.scl_out(0);
		}

		bool wait_() const {
			uint16_t cnt = busy_;
			port_.scl_dir(0);
			while(port_.scl_inp() == 0) {
				utils::delay::micro_second(1);
				if(cnt) {
					--cnt;
				} else {
					port_.scl_dir(1);
					return false;  // wait stall
				}
			}
			port_.scl_dir(1);
			return true;
		}

		void stop_() const {
			utils::delay::micro_second(clock_);
			port_.scl_out(1);
			utils::delay::micro_second(clock_);
			port_.sda_out(1);
		}

		bool write_(uint8_t val, bool sync) const {
			for(uint8_t n = 0; n < 8; ++n) {
				port_.sda_out(val & 0x80);
				utils::delay::micro_second(clock_);
				port_.scl_out(1);
				if(n == 0 && sync) {
					if(!wait_()) return false;
				}
				val <<= 1;
				utils::delay::micro_second(clock_);
				port_.scl_out(0);
			}
			return true;
		}

		bool write_(uint8_t data) const {
			if(!write_(data, true)) {
				stop_();
				return false;
			}
			if(ack_()) {
				stop_();
				return false;
			}
			return true;
		}

		bool write_(const uint8_t* src, uint8_t num) const {
			for(uint8_t n = 0; n < num; ++n) {
				if(!write_(*src, true)) {
					stop_();
					return false;
				}
				++src;
				if(ack_()) {
					stop_();
					return false;
				}
			}
			return true;
		}

		bool read_(uint8_t& val, bool sync) const {
			port_.sda_dir(0);
			for(uint8_t n = 0; n < 8; ++n) {
				utils::delay::micro_second(clock_);
				val <<= 1;
				port_.scl_out(1);
				if(n == 0 && sync) {
					if(!wait_()) {
						port_.sda_dir(1);
						return false;
					}
				}
				utils::delay::micro_second(clock_);
				if(port_.sda_inp()) val |= 1;
				port_.scl_out(0);
			}
			port_.sda_dir(1);
			return true;
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		i2c_io() : clock_(slow_clock_), busy_(200) { }

		//-----------------------------------------------------------------//
		/*!
			@brief  初期化
		*/
		//-----------------------------------------------------------------//
		void init() const {
			port_.init();
			port_.scl_dir(1);
			port_.sda_dir(1);
			port_.scl_out(1);
			port_.sda_out(1);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  クロック設定
			@param[in]	clock	パルス５０％待ち時間（単位マイクロ秒）
		*/
		//-----------------------------------------------------------------//
		void set_clock(uint8_t clock) { clock_ = clock; }

		//-----------------------------------------------------------------//
		/*!
			@brief  低速指定（maybe 100KBPS）
		*/
		//-----------------------------------------------------------------//
		void set_slow() { clock_ = slow_clock_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  高速指定（maybe 400KBPS）
		*/
		//-----------------------------------------------------------------//
		void set_fast() { clock_ = fast_clock_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  スレーブデバイスの「待ち」時間の最大値を設定
			@param[in]	busy	待ち時間（単位マイクロ秒）
		*/
		//-----------------------------------------------------------------//
		void set_busy(uint16_t busy) { busy_ = busy; }

		//-----------------------------------------------------------------//
		/*!
			@brief  受信（リード）
			@param[in] address スレーブアドレス（７ビット）
			@param[out]	dst	先
			@param[in]	num	数
			@return 失敗なら「false」が返る
		*/
		//-----------------------------------------------------------------//
		bool recv(uint8_t address, uint8_t* dst, uint8_t num) const {
			start_();
			write_((address << 1) | 1, false);
			if(ack_()) {
				stop_();
				return false;
			}

			for(uint8_t n = 0; n < num; ++n) {
				if(!read_(*dst, true)) {
					stop_();
					return false;
				}
				bool f = 0;
				if(n == (num - 1)) f = 1;
				out_ack_(f);
				++dst;
			}
			stop_();
			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  送信（ライト）
			@param[in] address スレーブアドレス（７ビット）
			@param[in]	src	元
			@param[in]	num	数
			@return 失敗なら「false」が返る
		*/
		//-----------------------------------------------------------------//
		bool send(uint8_t address, const uint8_t* src, uint8_t num) const {
			start_();
			write_(address << 1, false);
			if(ack_()) {
				stop_();
				return false;
			}

			if(!write_(src, num)) {
				stop_();
				return false;
			}
			stop_();
			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  送信（ライト）
			@param[in] address スレーブアドレス（７ビット）
			@param[in]	first	ファーストデータ
			@param[in]	src	元
			@param[in]	num	数
			@return 失敗なら「false」が返る
		*/
		//-----------------------------------------------------------------//
		bool send(uint8_t address, uint8_t first, const uint8_t* src, uint8_t num) const {
			start_();
			write_(address << 1, false);
			if(ack_()) {
				stop_();
				return false;
			}

			if(!write_(first)) {
				stop_();
				return false;
			}

			if(!write_(src, num)) {
				stop_();
				return false;
			}
			stop_();
			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  送信（ライト）
			@param[in] address スレーブアドレス（７ビット）
			@param[in]	first	ファースト・データ
			@param[in]	second	セカンド・データ
			@param[in]	src	元
			@param[in]	num	数
			@return 失敗なら「false」が返る
		*/
		//-----------------------------------------------------------------//
		bool send(uint8_t address, uint8_t first, uint8_t second, const uint8_t* src, uint8_t num) const {
			start_();
			write_(address << 1, false);
			if(ack_()) {
				stop_();
				return false;
			}

			if(!write_(first)) {
				stop_();
				return false;
			}
			if(!write_(second)) {
				stop_();
				return false;
			}
			if(!write_(src, num)) {
				stop_();
				return false;
			}
			stop_();
			return true;
		}
	};
}
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	RL78/G13 グループ SD カード・アクセス制御 @n
			Copyright 2016 Kunihito Hiramatsu
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include "common/port_utils.hpp"
#include "ff12a/mmc_io.hpp"
#include "common/format.hpp"

namespace utils {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  SD カード・アクセス制御テンプレート
		@param[in]	CSI		CSI 制御クラス
		@param[in]	SELECT	SD カード選択 I/O ポートクラス
		@param[in]	POWER	SD カード電源 I/O ポートクラス
		@param[in]	DETECT	SD カード検出 I/O ポートクラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class CSI, class SELECT, class POWER, class DETECT>
	class sdc_io {
	public:
		typedef CSI csi_type;
		typedef fatfs::mmc_io<CSI, SELECT> mmc_type;

	private:
		CSI&	csi_;

		fatfs::mmc_io<CSI, SELECT> mmc_;

		FATFS	fatfs_;  ///< FatFS コンテキスト

		uint8_t	mount_delay_;
		bool	cd_;
		bool	mount_;

		// CSI 開始
		// ※SD カードのアクセスでは、「PHASE::TYPE4」を選択する。
		void start_csi_()
		{
			uint8_t intr_level = 0;
			if(!csi_.start(16000000, CSI::PHASE::TYPE4, intr_level)) {
				format("CSI Start fail ! (Clock spped over range)\n");
			}
		}

		static void dir_list_func_(const char* name, uint32_t size, bool dir) {
			if(dir) {
				format("          /%s\n") % name;
			} else {
				format("%8d  %s\n") % size % name;
			}
		}

	public:
///		typedef std::function<void (const char* name, uint32_t size, bool dir)> dir_loop_func;
		typedef void (*dir_loop_func)(const char* name, uint32_t size, bool dir);

		//-----------------------------------------------------------------//
		/*!
			@brief	コンストラクター
		 */
		//-----------------------------------------------------------------//
		sdc_io(CSI& csi) : csi_(csi), mmc_(csi_),
			mount_delay_(0), cd_(false), mount_(false) { }

		//-----------------------------------------------------------------//
		/*!
			@brief	初期化
		 */
		//-----------------------------------------------------------------//
		void initialize()
		{
			SELECT::PMC = 0;
			SELECT::PM = 0;
			SELECT::P = 0;  // 電源ＯＦＦ時、「０」にしておかないと電流が回り込む

			POWER::PMC = 0;
			POWER::PM = 0;
			POWER::P = 1;

			DETECT::PM = 1;  // input
			DETECT::POM = 0;
			DETECT::PU = 1;  // pull-up

			// CSI を初期化後、廃棄する事で関係ポートを初期化する。
			start_csi_();
			csi_.destroy();

			mount_ = false;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	SD カードのディレクトリーを取り、タスクを実行する
			@param[in]	root	ルート・パス
			@param[in]	func	実行関数
			@return ファイル数
		 */
		//-----------------------------------------------------------------//
		uint16_t dir_loop(const char* root, dir_loop_func func)
		{
			if(!mount_) return 0;

			uint16_t num = 0;
			DIR dir;
			auto st = f_opendir(&dir, root);
			if(st != FR_OK) {
				format("Can't open dir(%d): '%s'\n") % static_cast<uint32_t>(st) % root;
			} else {
				for(;;) {
					FILINFO fno;
					// Read a directory item
					if(f_readdir(&dir, &fno) != FR_OK) {
						format("Can't read dir\n");
						break;
					}
					if(!fno.fname[0]) break;
						if(fno.fattrib & AM_DIR) {
						func(fno.fname, static_cast<uint32_t>(fno.fsize), true);
					} else {
						func(fno.fname, static_cast<uint32_t>(fno.fsize), false);
					}
					++num;
				}
			}
			return num;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	SD カードのディレクトリーをリストする
			@param[in]	root	ルート・パス
			@return ファイル数
		 */
		//-----------------------------------------------------------------//
		uint16_t dir(const char* root)
		{
			return dir_loop(root, dir_list_func_);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	SD カードアクセス・サービス（毎フレーム呼ぶ）
			@return マウントしている場合「true」
		 */
		//-----------------------------------------------------------------//
		bool service()
		{
			auto st = !DETECT::P();
			if(!cd_ && st) {
				start_csi_();
				mount_delay_ = 10;  // 10 フレーム後にマウントする
				POWER::P = 0;
				SELECT::P = 1;
//				format("Card ditect\n");
			} else if(cd_ && !st) {
				f_mount(&fatfs_, "", 0);
				csi_.destroy();
				POWER::P = 1;
				SELECT::P = 0;
				mount_ = false;
//				format("Card unditect\n");
			}
			cd_ = st;

			if(mount_delay_) {
				--mount_delay_;
				if(mount_delay_ == 0) {
					auto st = f_mount(&fatfs_, "", 1);
					if(st != FR_OK) {
						format("Mount fail: %d\n") % static_cast<uint32_t>(st);
						csi_.destroy();
						POWER::P = 1;
						SELECT::P = 0;
						mount_ = false;
					} else {
						mount_ = true;
					}
				}
			}
			return mount_;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	カードのマウント状態を取得
			@return 「true」ならマウント状態
		 */
		//-----------------------------------------------------------------//
		bool get_mount() const { return mount_; }

		//-----------------------------------------------------------------//
		/*!
			@brief	MMC クラスを参照で返す
			@return MMC クラス
		 */
		//-----------------------------------------------------------------//
		mmc_type& at_mmc() { return mmc_; }
	};
}
<commit_msg>add directory traverse<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	RL78/G13 グループ SD カード・アクセス制御 @n
			Copyright 2016 Kunihito Hiramatsu
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include "common/port_utils.hpp"
#include "ff12a/mmc_io.hpp"
#include "common/format.hpp"

namespace utils {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  SD カード・アクセス制御テンプレート
		@param[in]	CSI		CSI 制御クラス
		@param[in]	SELECT	SD カード選択 I/O ポートクラス
		@param[in]	POWER	SD カード電源 I/O ポートクラス
		@param[in]	DETECT	SD カード検出 I/O ポートクラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class CSI, class SELECT, class POWER, class DETECT>
	class sdc_io {
	public:
		typedef CSI csi_type;
		typedef fatfs::mmc_io<CSI, SELECT> mmc_type;

	private:
		static const int path_buff_size_ = 256;

		CSI&	csi_;

		fatfs::mmc_io<CSI, SELECT> mmc_;

		FATFS	fatfs_;  ///< FatFS コンテキスト

		uint8_t	mount_delay_;
		bool	cd_;
		bool	mount_;

		char	current_[path_buff_size_];

		// CSI 開始
		// ※SD カードのアクセスでは、「PHASE::TYPE4」を選択する。
		void start_csi_()
		{
			uint8_t intr_level = 0;
			if(!csi_.start(16000000, CSI::PHASE::TYPE4, intr_level)) {
				format("CSI Start fail ! (Clock spped over range)\n");
			}
		}

		static void dir_list_func_(const char* name, uint32_t size, bool dir) {
			if(dir) {
				format("          /%s\n") % name;
			} else {
				format("%8d  %s\n") % size % name;
			}
		}

		void create_full_path_(char* full, const char* path) {
			std::strcpy(full, current_);
			if(path == nullptr || path[0] == 0) {
				if(full[0] == 0) {
					std::strcpy(full, "/");
				}
			} else if(std::strcmp(path, "..") == 0) {
				char* p = std::strrchr(full, '/');
				if(p != nullptr) {
					*p = 0;
				}
			} else if(path[0] == '/') {
				std::strcpy(full, path);
			} else {
				std::strcat(full, "/");
				std::strcat(full, path);
			}
		}

	public:
///		typedef std::function<void (const char* name, uint32_t size, bool dir)> dir_loop_func;
		typedef void (*dir_loop_func)(const char* name, uint32_t size, bool dir);

		//-----------------------------------------------------------------//
		/*!
			@brief	コンストラクター
		 */
		//-----------------------------------------------------------------//
		sdc_io(CSI& csi) : csi_(csi), mmc_(csi_),
			mount_delay_(0), cd_(false), mount_(false) { }

		//-----------------------------------------------------------------//
		/*!
			@brief	初期化
		 */
		//-----------------------------------------------------------------//
		void initialize()
		{
			SELECT::PMC = 0;
			SELECT::PM = 0;
			SELECT::P = 0;  // 電源ＯＦＦ時、「０」にしておかないと電流が回り込む

			POWER::PMC = 0;
			POWER::PM = 0;
			POWER::P = 1;

			DETECT::PM = 1;  // input
			DETECT::POM = 0;
			DETECT::PU = 1;  // pull-up

			// CSI を初期化後、廃棄する事で関係ポートを初期化する。
			start_csi_();
			csi_.destroy();

			mount_ = false;

			current_[0] = 0;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	カレント・パスの移動
			@param[in]	path	相対パス、又は、絶対パス
			@return 移動成功なら「true」
		 */
		//-----------------------------------------------------------------//
		bool cd(const char* path)
		{
			if(!mount_) return false;

			if(path == nullptr) return false;

			char full[path_buff_size_];
			create_full_path_(full, path);

			DIR dir;
			auto st = f_opendir(&dir, full);
			if(st != FR_OK) {
				return false;
			}
			std::strcpy(current_, full);

			f_closedir(&dir);
			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	SD カードのディレクトリーを取り、タスクを実行する
			@param[in]	root	ルート・パス
			@param[in]	func	実行関数
			@return ファイル数
		 */
		//-----------------------------------------------------------------//
		uint16_t dir_loop(const char* root, dir_loop_func func)
		{
			if(!mount_) return 0;

			char full[path_buff_size_];
			create_full_path_(full, root);

			uint16_t num = 0;
			DIR dir;
			auto st = f_opendir(&dir, full);
			if(st != FR_OK) {
				format("Can't open dir(%d): '%s'\n") % static_cast<uint32_t>(st) % root;
			} else {
				std::strcat(full, "/");
				char* p = &full[std::strlen(full)];
				for(;;) {
					FILINFO fno;
					// Read a directory item
					if(f_readdir(&dir, &fno) != FR_OK) {
						format("Can't read dir\n");
						break;
					}
					if(!fno.fname[0]) break;
					std::strcpy(p, fno.fname);
					if(fno.fattrib & AM_DIR) {
						func(p, static_cast<uint32_t>(fno.fsize), true);
					} else {
						func(p, static_cast<uint32_t>(fno.fsize), false);
					}
					++num;
				}
				f_closedir(&dir);
			}
			return num;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	SD カードのディレクトリーをリストする
			@param[in]	root	ルート・パス
			@return ファイル数
		 */
		//-----------------------------------------------------------------//
		uint16_t dir(const char* root)
		{
			return dir_loop(root, dir_list_func_);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	SD カードアクセス・サービス（毎フレーム呼ぶ）
			@return マウントしている場合「true」
		 */
		//-----------------------------------------------------------------//
		bool service()
		{
			auto st = !DETECT::P();
			if(!cd_ && st) {
				start_csi_();
				mount_delay_ = 10;  // 10 フレーム後にマウントする
				POWER::P = 0;
				SELECT::P = 1;
//				format("Card ditect\n");
			} else if(cd_ && !st) {
				f_mount(&fatfs_, "", 0);
				csi_.destroy();
				POWER::P = 1;
				SELECT::P = 0;
				mount_ = false;
//				format("Card unditect\n");
			}
			cd_ = st;

			if(mount_delay_) {
				--mount_delay_;
				if(mount_delay_ == 0) {
					auto st = f_mount(&fatfs_, "", 1);
					if(st != FR_OK) {
						format("Mount fail: %d\n") % static_cast<uint32_t>(st);
						csi_.destroy();
						POWER::P = 1;
						SELECT::P = 0;
						mount_ = false;
					} else {
						current_[0] = 0;
						mount_ = true;
					}
				}
			}
			return mount_;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	カレント・パスを取得
			@return カレント。パス
		 */
		//-----------------------------------------------------------------//
		const char* get_current() const { return current_; }

		//-----------------------------------------------------------------//
		/*!
			@brief	カードのマウント状態を取得
			@return 「true」ならマウント状態
		 */
		//-----------------------------------------------------------------//
		bool get_mount() const { return mount_; }

		//-----------------------------------------------------------------//
		/*!
			@brief	MMC クラスを参照で返す
			@return MMC クラス
		 */
		//-----------------------------------------------------------------//
		mmc_type& at_mmc() { return mmc_; }
	};
}
<|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.
//
// This test creates a fake safebrowsing service, where we can inject
// malware and phishing urls.  It then uses a real browser to go to
// these urls, and sends "goback" or "proceed" commands and verifies
// they work.

#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"

// A SafeBrowingService class that allows us to inject the malicious URLs.
class FakeSafeBrowsingService :  public SafeBrowsingService {
 public:
  FakeSafeBrowsingService() {}

  virtual ~FakeSafeBrowsingService() {}

  // Called on the IO thread to check if the given url is safe or not.  If we
  // can synchronously determine that the url is safe, CheckUrl returns true.
  // Otherwise it returns false, and "client" is called asynchronously with the
  // result when it is ready.
  // Overrides SafeBrowsingService::CheckUrl.
  virtual bool CheckUrl(const GURL& gurl, Client* client) {
    const std::string& url = gurl.spec();
    if (badurls[url] == URL_SAFE)
      return true;

    BrowserThread::PostTask(
        BrowserThread::IO, FROM_HERE,
        NewRunnableMethod(this, &FakeSafeBrowsingService::OnCheckDone,
                          url, client));
    return false;
  }

  void OnCheckDone(std::string url, Client* client) {
    client->OnUrlCheckResult(GURL(url), badurls[url]);
  }

  void AddURLResult(const GURL& url, UrlCheckResult checkresult) {
    badurls[url.spec()] = checkresult;
  }

 private:
  base::hash_map<std::string, UrlCheckResult> badurls;
};

// Factory that creates FakeSafeBrowsingService instances.
class TestSafeBrowsingServiceFactory : public SafeBrowsingServiceFactory {
 public:
  TestSafeBrowsingServiceFactory() { }
  virtual ~TestSafeBrowsingServiceFactory() { }

  virtual SafeBrowsingService* CreateSafeBrowsingService() {
    return new FakeSafeBrowsingService();
  }
};

// Tests the safe browsing blocking page in a browser.
class SafeBrowsingBlockingPageTest : public InProcessBrowserTest,
                                     public SafeBrowsingService::Client {
 public:
  SafeBrowsingBlockingPageTest() {
  }

  virtual void SetUp() {
    SafeBrowsingService::RegisterFactory(&factory);
    InProcessBrowserTest::SetUp();
  }

  virtual void TearDown() {
    InProcessBrowserTest::TearDown();
    SafeBrowsingService::RegisterFactory(NULL);
  }

  virtual void SetUpInProcessBrowserTestFixture() {
    ASSERT_TRUE(test_server()->Start());
  }

  // SafeBrowsingService::Client implementation.
  virtual void OnUrlCheckResult(const GURL& url,
                                SafeBrowsingService::UrlCheckResult result) {
  }
  virtual void OnBlockingPageComplete(bool proceed) {
  }

  void AddURLResult(const GURL& url,
                    SafeBrowsingService::UrlCheckResult checkresult) {
    FakeSafeBrowsingService* service =
        static_cast<FakeSafeBrowsingService*>(
            g_browser_process->resource_dispatcher_host()->
            safe_browsing_service());

    ASSERT_TRUE(service != NULL);
    service->AddURLResult(url, checkresult);
  }

  void SendCommand(const std::string& command) {
    TabContents* contents = browser()->GetSelectedTabContents();
    SafeBrowsingBlockingPage* interstitial_page =
        static_cast<SafeBrowsingBlockingPage*>(
            contents->interstitial_page());
    ASSERT_TRUE(interstitial_page);
    interstitial_page->CommandReceived(command);
  }

  void DontProceedThroughInterstitial() {
    TabContents* contents = browser()->GetSelectedTabContents();
    InterstitialPage* interstitial_page = contents->interstitial_page();
    ASSERT_TRUE(interstitial_page);
    interstitial_page->DontProceed();
  }

  void ProceedThroughInterstitial() {
    TabContents* contents = browser()->GetSelectedTabContents();
    InterstitialPage* interstitial_page = contents->interstitial_page();
    ASSERT_TRUE(interstitial_page);
    interstitial_page->Proceed();
  }

  void AssertNoInterstitial() {
    TabContents* contents = browser()->GetSelectedTabContents();
    InterstitialPage* interstitial_page = contents->interstitial_page();
    ASSERT_FALSE(interstitial_page);
  }

  void WaitForNavigation() {
    NavigationController* controller =
        &browser()->GetSelectedTabContents()->controller();
    ui_test_utils::WaitForNavigation(controller);
  }

 private:
  TestSafeBrowsingServiceFactory factory;

  DISALLOW_COPY_AND_ASSIGN(SafeBrowsingBlockingPageTest);
};

namespace {

const char kEmptyPage[] = "files/empty.html";
const char kMalwarePage[] = "files/safe_browsing/malware.html";
const char kMalwareIframe[] = "files/safe_browsing/malware_iframe.html";

IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, MalwareDontProceed) {
  GURL url = test_server()->GetURL(kEmptyPage);
  AddURLResult(url, SafeBrowsingService::URL_MALWARE);

  ui_test_utils::NavigateToURL(browser(), url);

  SendCommand("\"takeMeBack\"");   // Simulate the user clicking "back"
  AssertNoInterstitial();   // Assert the interstitial is gone
  EXPECT_EQ(GURL(chrome::kAboutBlankURL),   // Back to "about:blank"
            browser()->GetSelectedTabContents()->GetURL());
}

IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, MalwareProceed) {
  GURL url = test_server()->GetURL(kEmptyPage);
  AddURLResult(url, SafeBrowsingService::URL_MALWARE);

  ui_test_utils::NavigateToURL(browser(), url);

  SendCommand("\"proceed\"");    // Simulate the user clicking "proceed"
  WaitForNavigation();    // Wait until we finish the navigation.
  AssertNoInterstitial();    // Assert the interstitial is gone.
  EXPECT_EQ(url, browser()->GetSelectedTabContents()->GetURL());
}

IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, PhishingDontProceed) {
  GURL url = test_server()->GetURL(kEmptyPage);
  AddURLResult(url, SafeBrowsingService::URL_PHISHING);

  ui_test_utils::NavigateToURL(browser(), url);

  SendCommand("\"takeMeBack\"");   // Simulate the user clicking "proceed"
  AssertNoInterstitial();    // Assert the interstitial is gone
  EXPECT_EQ(GURL(chrome::kAboutBlankURL),  // We are back to "about:blank".
            browser()->GetSelectedTabContents()->GetURL());
}

IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, PhishingProceed) {
  GURL url = test_server()->GetURL(kEmptyPage);
  AddURLResult(url, SafeBrowsingService::URL_PHISHING);

  ui_test_utils::NavigateToURL(browser(), url);

  SendCommand("\"proceed\"");   // Simulate the user clicking "proceed".
  WaitForNavigation();    // Wait until we finish the navigation.
  AssertNoInterstitial();    // Assert the interstitial is gone
  EXPECT_EQ(url, browser()->GetSelectedTabContents()->GetURL());
}

IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, PhishingReportError) {
  GURL url = test_server()->GetURL(kEmptyPage);
  AddURLResult(url, SafeBrowsingService::URL_PHISHING);

  ui_test_utils::NavigateToURL(browser(), url);

  SendCommand("\"reportError\"");   // Simulate the user clicking "report error"
  WaitForNavigation();    // Wait until we finish the navigation.
  AssertNoInterstitial();    // Assert the interstitial is gone

  // We are in the error reporting page.
  EXPECT_EQ("/safebrowsing/report_error/",
            browser()->GetSelectedTabContents()->GetURL().path());
}

IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, PhishingLearnMore) {
  GURL url = test_server()->GetURL(kEmptyPage);
  AddURLResult(url, SafeBrowsingService::URL_PHISHING);

  ui_test_utils::NavigateToURL(browser(), url);

  SendCommand("\"learnMore\"");   // Simulate the user clicking "learn more"
  WaitForNavigation();    // Wait until we finish the navigation.
  AssertNoInterstitial();    // Assert the interstitial is gone

  // We are in the help page.
  EXPECT_EQ("/support/bin/answer.py",
            browser()->GetSelectedTabContents()->GetURL().path());
}

IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, MalwareIframeDontProceed) {
  GURL url = test_server()->GetURL(kMalwarePage);
  GURL iframe_url = test_server()->GetURL(kMalwareIframe);
  AddURLResult(iframe_url, SafeBrowsingService::URL_MALWARE);

  ui_test_utils::NavigateToURL(browser(), url);

  SendCommand("\"takeMeBack\"");    // Simulate the user clicking "back"
  AssertNoInterstitial();  // Assert the interstitial is gone

  EXPECT_EQ(GURL(chrome::kAboutBlankURL),    // Back to "about:blank"
            browser()->GetSelectedTabContents()->GetURL());
}

IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, MalwareIframeProceed) {
  GURL url = test_server()->GetURL(kMalwarePage);
  GURL iframe_url = test_server()->GetURL(kMalwareIframe);
  AddURLResult(iframe_url, SafeBrowsingService::URL_MALWARE);

  ui_test_utils::NavigateToURL(browser(), url);

  SendCommand("\"proceed\"");   // Simulate the user clicking "proceed"
  AssertNoInterstitial();    // Assert the interstitial is gone

  EXPECT_EQ(url, browser()->GetSelectedTabContents()->GetURL());
}

}  // namespace
<commit_msg>Disable phishing tests that appear to fail because of log parsing bug.<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.
//
// This test creates a fake safebrowsing service, where we can inject
// malware and phishing urls.  It then uses a real browser to go to
// these urls, and sends "goback" or "proceed" commands and verifies
// they work.

#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"

// A SafeBrowingService class that allows us to inject the malicious URLs.
class FakeSafeBrowsingService :  public SafeBrowsingService {
 public:
  FakeSafeBrowsingService() {}

  virtual ~FakeSafeBrowsingService() {}

  // Called on the IO thread to check if the given url is safe or not.  If we
  // can synchronously determine that the url is safe, CheckUrl returns true.
  // Otherwise it returns false, and "client" is called asynchronously with the
  // result when it is ready.
  // Overrides SafeBrowsingService::CheckUrl.
  virtual bool CheckUrl(const GURL& gurl, Client* client) {
    const std::string& url = gurl.spec();
    if (badurls[url] == URL_SAFE)
      return true;

    BrowserThread::PostTask(
        BrowserThread::IO, FROM_HERE,
        NewRunnableMethod(this, &FakeSafeBrowsingService::OnCheckDone,
                          url, client));
    return false;
  }

  void OnCheckDone(std::string url, Client* client) {
    client->OnUrlCheckResult(GURL(url), badurls[url]);
  }

  void AddURLResult(const GURL& url, UrlCheckResult checkresult) {
    badurls[url.spec()] = checkresult;
  }

 private:
  base::hash_map<std::string, UrlCheckResult> badurls;
};

// Factory that creates FakeSafeBrowsingService instances.
class TestSafeBrowsingServiceFactory : public SafeBrowsingServiceFactory {
 public:
  TestSafeBrowsingServiceFactory() { }
  virtual ~TestSafeBrowsingServiceFactory() { }

  virtual SafeBrowsingService* CreateSafeBrowsingService() {
    return new FakeSafeBrowsingService();
  }
};

// Tests the safe browsing blocking page in a browser.
class SafeBrowsingBlockingPageTest : public InProcessBrowserTest,
                                     public SafeBrowsingService::Client {
 public:
  SafeBrowsingBlockingPageTest() {
  }

  virtual void SetUp() {
    SafeBrowsingService::RegisterFactory(&factory);
    InProcessBrowserTest::SetUp();
  }

  virtual void TearDown() {
    InProcessBrowserTest::TearDown();
    SafeBrowsingService::RegisterFactory(NULL);
  }

  virtual void SetUpInProcessBrowserTestFixture() {
    ASSERT_TRUE(test_server()->Start());
  }

  // SafeBrowsingService::Client implementation.
  virtual void OnUrlCheckResult(const GURL& url,
                                SafeBrowsingService::UrlCheckResult result) {
  }
  virtual void OnBlockingPageComplete(bool proceed) {
  }

  void AddURLResult(const GURL& url,
                    SafeBrowsingService::UrlCheckResult checkresult) {
    FakeSafeBrowsingService* service =
        static_cast<FakeSafeBrowsingService*>(
            g_browser_process->resource_dispatcher_host()->
            safe_browsing_service());

    ASSERT_TRUE(service != NULL);
    service->AddURLResult(url, checkresult);
  }

  void SendCommand(const std::string& command) {
    TabContents* contents = browser()->GetSelectedTabContents();
    SafeBrowsingBlockingPage* interstitial_page =
        static_cast<SafeBrowsingBlockingPage*>(
            contents->interstitial_page());
    ASSERT_TRUE(interstitial_page);
    interstitial_page->CommandReceived(command);
  }

  void DontProceedThroughInterstitial() {
    TabContents* contents = browser()->GetSelectedTabContents();
    InterstitialPage* interstitial_page = contents->interstitial_page();
    ASSERT_TRUE(interstitial_page);
    interstitial_page->DontProceed();
  }

  void ProceedThroughInterstitial() {
    TabContents* contents = browser()->GetSelectedTabContents();
    InterstitialPage* interstitial_page = contents->interstitial_page();
    ASSERT_TRUE(interstitial_page);
    interstitial_page->Proceed();
  }

  void AssertNoInterstitial() {
    TabContents* contents = browser()->GetSelectedTabContents();
    InterstitialPage* interstitial_page = contents->interstitial_page();
    ASSERT_FALSE(interstitial_page);
  }

  void WaitForNavigation() {
    NavigationController* controller =
        &browser()->GetSelectedTabContents()->controller();
    ui_test_utils::WaitForNavigation(controller);
  }

 private:
  TestSafeBrowsingServiceFactory factory;

  DISALLOW_COPY_AND_ASSIGN(SafeBrowsingBlockingPageTest);
};

namespace {

const char kEmptyPage[] = "files/empty.html";
const char kMalwarePage[] = "files/safe_browsing/malware.html";
const char kMalwareIframe[] = "files/safe_browsing/malware_iframe.html";

IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, MalwareDontProceed) {
  GURL url = test_server()->GetURL(kEmptyPage);
  AddURLResult(url, SafeBrowsingService::URL_MALWARE);

  ui_test_utils::NavigateToURL(browser(), url);

  SendCommand("\"takeMeBack\"");   // Simulate the user clicking "back"
  AssertNoInterstitial();   // Assert the interstitial is gone
  EXPECT_EQ(GURL(chrome::kAboutBlankURL),   // Back to "about:blank"
            browser()->GetSelectedTabContents()->GetURL());
}

IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, MalwareProceed) {
  GURL url = test_server()->GetURL(kEmptyPage);
  AddURLResult(url, SafeBrowsingService::URL_MALWARE);

  ui_test_utils::NavigateToURL(browser(), url);

  SendCommand("\"proceed\"");    // Simulate the user clicking "proceed"
  WaitForNavigation();    // Wait until we finish the navigation.
  AssertNoInterstitial();    // Assert the interstitial is gone.
  EXPECT_EQ(url, browser()->GetSelectedTabContents()->GetURL());
}

// Disabled because of bug in parsing output: 64792.
#if defined(OS_WIN)
#define MAYBE_PhishingDontProceed DISABLED_PhishingDontProceed
#else
#define MAYBE_PhishingDontProceed PhishingDontProceed
#endif
IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest,
                       MAYBE_PhishingDontProceed) {
  GURL url = test_server()->GetURL(kEmptyPage);
  AddURLResult(url, SafeBrowsingService::URL_PHISHING);

  ui_test_utils::NavigateToURL(browser(), url);

  SendCommand("\"takeMeBack\"");   // Simulate the user clicking "proceed"
  AssertNoInterstitial();    // Assert the interstitial is gone
  EXPECT_EQ(GURL(chrome::kAboutBlankURL),  // We are back to "about:blank".
            browser()->GetSelectedTabContents()->GetURL());
}

IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, PhishingProceed) {
  GURL url = test_server()->GetURL(kEmptyPage);
  AddURLResult(url, SafeBrowsingService::URL_PHISHING);

  ui_test_utils::NavigateToURL(browser(), url);

  SendCommand("\"proceed\"");   // Simulate the user clicking "proceed".
  WaitForNavigation();    // Wait until we finish the navigation.
  AssertNoInterstitial();    // Assert the interstitial is gone
  EXPECT_EQ(url, browser()->GetSelectedTabContents()->GetURL());
}

// Disabled because of bug in parsing output: 64792.
#if defined(OS_WIN)
#define MAYBE_PhishingReportError DISABLED_PhishingReportError
#else
#define MAYBE_PhishingReportError PhishingReportError
#endif
IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest,
                       MAYBE_PhishingReportError) {
  GURL url = test_server()->GetURL(kEmptyPage);
  AddURLResult(url, SafeBrowsingService::URL_PHISHING);

  ui_test_utils::NavigateToURL(browser(), url);

  SendCommand("\"reportError\"");   // Simulate the user clicking "report error"
  WaitForNavigation();    // Wait until we finish the navigation.
  AssertNoInterstitial();    // Assert the interstitial is gone

  // We are in the error reporting page.
  EXPECT_EQ("/safebrowsing/report_error/",
            browser()->GetSelectedTabContents()->GetURL().path());
}

// Disabled because of bug in parsing output: 64792.
#if defined(OS_WIN)
#define MAYBE_PhishingLearnMore DISABLED_PhishingLearnMore
#else
#define MAYBE_PhishingLearnMore PhishingLearnMore
#endif
IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, MAYBE_PhishingLearnMore) {
  GURL url = test_server()->GetURL(kEmptyPage);
  AddURLResult(url, SafeBrowsingService::URL_PHISHING);

  ui_test_utils::NavigateToURL(browser(), url);

  SendCommand("\"learnMore\"");   // Simulate the user clicking "learn more"
  WaitForNavigation();    // Wait until we finish the navigation.
  AssertNoInterstitial();    // Assert the interstitial is gone

  // We are in the help page.
  EXPECT_EQ("/support/bin/answer.py",
            browser()->GetSelectedTabContents()->GetURL().path());
}

IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, MalwareIframeDontProceed) {
  GURL url = test_server()->GetURL(kMalwarePage);
  GURL iframe_url = test_server()->GetURL(kMalwareIframe);
  AddURLResult(iframe_url, SafeBrowsingService::URL_MALWARE);

  ui_test_utils::NavigateToURL(browser(), url);

  SendCommand("\"takeMeBack\"");    // Simulate the user clicking "back"
  AssertNoInterstitial();  // Assert the interstitial is gone

  EXPECT_EQ(GURL(chrome::kAboutBlankURL),    // Back to "about:blank"
            browser()->GetSelectedTabContents()->GetURL());
}

IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, MalwareIframeProceed) {
  GURL url = test_server()->GetURL(kMalwarePage);
  GURL iframe_url = test_server()->GetURL(kMalwareIframe);
  AddURLResult(iframe_url, SafeBrowsingService::URL_MALWARE);

  ui_test_utils::NavigateToURL(browser(), url);

  SendCommand("\"proceed\"");   // Simulate the user clicking "proceed"
  AssertNoInterstitial();    // Assert the interstitial is gone

  EXPECT_EQ(url, browser()->GetSelectedTabContents()->GetURL());
}

}  // namespace
<|endoftext|>


<commit_before>// Copyright (c) 2009 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 entry.

#include "chrome/browser/sync/util/extensions_activity_monitor.h"

#include "base/file_path.h"
#include "base/string_util.h"
#include "base/waitable_event.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/extension_bookmarks_module.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/notification_service.h"
#include "testing/gtest/include/gtest/gtest.h"

using browser_sync::ExtensionsActivityMonitor;
namespace keys = extension_manifest_keys;

namespace {

static const char* kTestExtensionPath1 = "c:\\testextension1";
static const char* kTestExtensionPath2 = "c:\\testextension2";
static const char* kTestExtensionVersion = "1.0.0.0";
static const char* kTestExtensionName = "foo extension";

template <class FunctionType>
class BookmarkAPIEventTask : public Task {
 public:
  BookmarkAPIEventTask(FunctionType* t, Extension* e, size_t repeats,
                       base::WaitableEvent* done) :
       function_(t), extension_(e), repeats_(repeats), done_(done) {}
   virtual void Run() {
     for (size_t i = 0; i < repeats_; i++) {
       NotificationService::current()->Notify(
           NotificationType::EXTENSION_BOOKMARKS_API_INVOKED,
           Source<Extension>(extension_.get()),
           Details<const BookmarksFunction>(function_.get()));
     }
     done_->Signal();
   }
 private:
  scoped_ptr<Extension> extension_;
  scoped_refptr<FunctionType> function_;
  size_t repeats_;
  base::WaitableEvent* done_;

  DISALLOW_COPY_AND_ASSIGN(BookmarkAPIEventTask);
};

class BookmarkAPIEventGenerator {
 public:
  BookmarkAPIEventGenerator(MessageLoop* ui_loop) : ui_loop_(ui_loop) {}
  virtual ~BookmarkAPIEventGenerator() {}
  template <class T>
  void NewEvent(const std::string& extension_path,
      T* bookmarks_function, size_t repeats) {
    FilePath path(UTF8ToWide(extension_path));
    Extension* extension = new Extension(path);
    std::string error;
    DictionaryValue input;
    input.SetString(keys::kVersion, kTestExtensionVersion);
    input.SetString(keys::kName, kTestExtensionName);
    extension->InitFromValue(input, false, &error);
    bookmarks_function->set_name(T::function_name());
    base::WaitableEvent done_event(false, false);
    ui_loop_->PostTask(FROM_HERE, new BookmarkAPIEventTask<T>(
        bookmarks_function, extension, repeats, &done_event));
    done_event.Wait();
  }

 private:
  MessageLoop* ui_loop_;
  DISALLOW_COPY_AND_ASSIGN(BookmarkAPIEventGenerator);
};
}  // namespace

class DoUIThreadSetupTask : public Task {
 public:
  DoUIThreadSetupTask(NotificationService** service,
                      base::WaitableEvent* done)
      : service_(service), signal_when_done_(done) {}
  virtual ~DoUIThreadSetupTask() {}
  virtual void Run() {
    *service_ = new NotificationService();
    signal_when_done_->Signal();
  }
 private:
  NotificationService** service_;
  base::WaitableEvent* signal_when_done_;
  DISALLOW_COPY_AND_ASSIGN(DoUIThreadSetupTask);
};

class ExtensionsActivityMonitorTest : public testing::Test {
 public:
  ExtensionsActivityMonitorTest() : service_(NULL),
      ui_thread_(ChromeThread::UI) { }
  virtual ~ExtensionsActivityMonitorTest() {}

  virtual void SetUp() {
    ui_thread_.Start();
    base::WaitableEvent service_created(false, false);
    ui_thread_.message_loop()->PostTask(FROM_HERE,
        new DoUIThreadSetupTask(&service_, &service_created));
    service_created.Wait();
  }

  virtual void TearDown() {
    ui_thread_.message_loop()->DeleteSoon(FROM_HERE, service_);
    ui_thread_.Stop();
  }

  MessageLoop* ui_loop() { return ui_thread_.message_loop(); }

  static std::string GetExtensionIdForPath(const std::string& extension_path) {
    std::string error;
    FilePath path(UTF8ToWide(extension_path));
    Extension e(path);
    DictionaryValue input;
    input.SetString(keys::kVersion, kTestExtensionVersion);
    input.SetString(keys::kName, kTestExtensionName);
    e.InitFromValue(input, false, &error);
    EXPECT_EQ("", error);
    return e.id();
  }
 private:
  NotificationService* service_;
  ChromeThread ui_thread_;
};

TEST_F(ExtensionsActivityMonitorTest, Basic) {
  ExtensionsActivityMonitor* monitor = new ExtensionsActivityMonitor(ui_loop());
  BookmarkAPIEventGenerator generator(ui_loop());

  generator.NewEvent<RemoveBookmarkFunction>(kTestExtensionPath1,
      new RemoveBookmarkFunction(), 1);
  generator.NewEvent<MoveBookmarkFunction>(kTestExtensionPath1,
      new MoveBookmarkFunction(), 1);
  generator.NewEvent<UpdateBookmarkFunction>(kTestExtensionPath1,
      new UpdateBookmarkFunction(), 2);
  generator.NewEvent<CreateBookmarkFunction>(kTestExtensionPath1,
      new CreateBookmarkFunction(), 3);
  generator.NewEvent<SearchBookmarksFunction>(kTestExtensionPath1,
      new SearchBookmarksFunction(), 5);
  const int writes_by_extension1 = 1 + 1 + 2 + 3;

  generator.NewEvent<RemoveTreeBookmarkFunction>(kTestExtensionPath2,
      new RemoveTreeBookmarkFunction(), 8);
  generator.NewEvent<GetBookmarkTreeFunction>(kTestExtensionPath2,
      new GetBookmarkTreeFunction(), 13);
  generator.NewEvent<GetBookmarkChildrenFunction>(kTestExtensionPath2,
      new GetBookmarkChildrenFunction(), 21);
  generator.NewEvent<GetBookmarksFunction>(kTestExtensionPath2,
      new GetBookmarksFunction(), 33);
  const int writes_by_extension2 = 8;

  ExtensionsActivityMonitor::Records results;
  monitor->GetAndClearRecords(&results);

  std::string id1 = GetExtensionIdForPath(kTestExtensionPath1);
  std::string id2 = GetExtensionIdForPath(kTestExtensionPath2);

  EXPECT_EQ(2, results.size());
  EXPECT_TRUE(results.end() != results.find(id1));
  EXPECT_TRUE(results.end() != results.find(id2));
  EXPECT_EQ(writes_by_extension1, results[id1].bookmark_write_count);
  EXPECT_EQ(writes_by_extension2, results[id2].bookmark_write_count);

  ui_loop()->DeleteSoon(FROM_HERE, monitor);
}

TEST_F(ExtensionsActivityMonitorTest, Put) {
  ExtensionsActivityMonitor* monitor = new ExtensionsActivityMonitor(ui_loop());
  BookmarkAPIEventGenerator generator(ui_loop());
  std::string id1 = GetExtensionIdForPath(kTestExtensionPath1);
  std::string id2 = GetExtensionIdForPath(kTestExtensionPath2);

  generator.NewEvent<CreateBookmarkFunction>(kTestExtensionPath1,
      new CreateBookmarkFunction(), 5);
  generator.NewEvent<MoveBookmarkFunction>(kTestExtensionPath2,
      new MoveBookmarkFunction(), 8);

  ExtensionsActivityMonitor::Records results;
  monitor->GetAndClearRecords(&results);

  EXPECT_EQ(2, results.size());
  EXPECT_EQ(5, results[id1].bookmark_write_count);
  EXPECT_EQ(8, results[id2].bookmark_write_count);

  generator.NewEvent<GetBookmarksFunction>(kTestExtensionPath2,
      new GetBookmarksFunction(), 3);
  generator.NewEvent<UpdateBookmarkFunction>(kTestExtensionPath2,
      new UpdateBookmarkFunction(), 2);

  // Simulate a commit failure, which augments the active record set with the
  // refugee records.
  monitor->PutRecords(results);
  ExtensionsActivityMonitor::Records new_records;
  monitor->GetAndClearRecords(&new_records);

  EXPECT_EQ(2, results.size());
  EXPECT_EQ(id1, new_records[id1].extension_id);
  EXPECT_EQ(id2, new_records[id2].extension_id);
  EXPECT_EQ(5, new_records[id1].bookmark_write_count);
  EXPECT_EQ(8 + 2, new_records[id2].bookmark_write_count);
  ui_loop()->DeleteSoon(FROM_HERE, monitor);
}

TEST_F(ExtensionsActivityMonitorTest, MultiGet) {
  ExtensionsActivityMonitor* monitor = new ExtensionsActivityMonitor(ui_loop());
  BookmarkAPIEventGenerator generator(ui_loop());
  std::string id1 = GetExtensionIdForPath(kTestExtensionPath1);

  generator.NewEvent<CreateBookmarkFunction>(kTestExtensionPath1,
      new CreateBookmarkFunction(), 5);

  ExtensionsActivityMonitor::Records results;
  monitor->GetAndClearRecords(&results);

  EXPECT_EQ(1, results.size());
  EXPECT_EQ(5, results[id1].bookmark_write_count);

  monitor->GetAndClearRecords(&results);
  EXPECT_TRUE(results.empty());

  generator.NewEvent<CreateBookmarkFunction>(kTestExtensionPath1,
      new CreateBookmarkFunction(), 3);
  monitor->GetAndClearRecords(&results);

  EXPECT_EQ(1, results.size());
  EXPECT_EQ(3, results[id1].bookmark_write_count);

  ui_loop()->DeleteSoon(FROM_HERE, monitor);
}
<commit_msg>Revert (1 of 4) 30157 - Add newline to end of another file.<commit_after>// Copyright (c) 2009 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 entry.

#include "chrome/browser/sync/util/extensions_activity_monitor.h"

#include "base/file_path.h"
#include "base/string_util.h"
#include "base/waitable_event.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/extension_bookmarks_module.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/notification_service.h"
#include "testing/gtest/include/gtest/gtest.h"

using browser_sync::ExtensionsActivityMonitor;
namespace keys = extension_manifest_keys;

namespace {

static const char* kTestExtensionPath1 = "c:\\testextension1";
static const char* kTestExtensionPath2 = "c:\\testextension2";
static const char* kTestExtensionVersion = "1.0.0.0";
static const char* kTestExtensionName = "foo extension";

template <class FunctionType>
class BookmarkAPIEventTask : public Task {
 public:
  BookmarkAPIEventTask(FunctionType* t, Extension* e, size_t repeats,
                       base::WaitableEvent* done) :
       function_(t), extension_(e), repeats_(repeats), done_(done) {}
   virtual void Run() {
     for (size_t i = 0; i < repeats_; i++) {
       NotificationService::current()->Notify(
           NotificationType::EXTENSION_BOOKMARKS_API_INVOKED,
           Source<Extension>(extension_.get()),
           Details<const BookmarksFunction>(function_.get()));
     }
     done_->Signal();
   }
 private:
  scoped_ptr<Extension> extension_;
  scoped_refptr<FunctionType> function_;
  size_t repeats_;
  base::WaitableEvent* done_;

  DISALLOW_COPY_AND_ASSIGN(BookmarkAPIEventTask);
};

class BookmarkAPIEventGenerator {
 public:
  BookmarkAPIEventGenerator(MessageLoop* ui_loop) : ui_loop_(ui_loop) {}
  virtual ~BookmarkAPIEventGenerator() {}
  template <class T>
  void NewEvent(const std::string& extension_path,
      T* bookmarks_function, size_t repeats) {
    FilePath path(UTF8ToWide(extension_path));
    Extension* extension = new Extension(path);
    std::string error;
    DictionaryValue input;
    input.SetString(keys::kVersion, kTestExtensionVersion);
    input.SetString(keys::kName, kTestExtensionName);
    extension->InitFromValue(input, false, &error);
    bookmarks_function->set_name(T::function_name());
    base::WaitableEvent done_event(false, false);
    ui_loop_->PostTask(FROM_HERE, new BookmarkAPIEventTask<T>(
        bookmarks_function, extension, repeats, &done_event));
    done_event.Wait();
  }

 private:
  MessageLoop* ui_loop_;
  DISALLOW_COPY_AND_ASSIGN(BookmarkAPIEventGenerator);
};
}  // namespace

class DoUIThreadSetupTask : public Task {
 public:
  DoUIThreadSetupTask(NotificationService** service,
                      base::WaitableEvent* done)
      : service_(service), signal_when_done_(done) {}
  virtual ~DoUIThreadSetupTask() {}
  virtual void Run() {
    *service_ = new NotificationService();
    signal_when_done_->Signal();
  }
 private:
  NotificationService** service_;
  base::WaitableEvent* signal_when_done_;
  DISALLOW_COPY_AND_ASSIGN(DoUIThreadSetupTask);
};

class ExtensionsActivityMonitorTest : public testing::Test {
 public:
  ExtensionsActivityMonitorTest() : service_(NULL),
      ui_thread_(ChromeThread::UI) { }
  virtual ~ExtensionsActivityMonitorTest() {}

  virtual void SetUp() {
    ui_thread_.Start();
    base::WaitableEvent service_created(false, false);
    ui_thread_.message_loop()->PostTask(FROM_HERE,
        new DoUIThreadSetupTask(&service_, &service_created));
    service_created.Wait();
  }

  virtual void TearDown() {
    ui_thread_.message_loop()->DeleteSoon(FROM_HERE, service_);
    ui_thread_.Stop();
  }

  MessageLoop* ui_loop() { return ui_thread_.message_loop(); }

  static std::string GetExtensionIdForPath(const std::string& extension_path) {
    std::string error;
    FilePath path(UTF8ToWide(extension_path));
    Extension e(path);
    DictionaryValue input;
    input.SetString(keys::kVersion, kTestExtensionVersion);
    input.SetString(keys::kName, kTestExtensionName);
    e.InitFromValue(input, false, &error);
    EXPECT_EQ("", error);
    return e.id();
  }
 private:
  NotificationService* service_;
  ChromeThread ui_thread_;
};

TEST_F(ExtensionsActivityMonitorTest, Basic) {
  ExtensionsActivityMonitor* monitor = new ExtensionsActivityMonitor(ui_loop());
  BookmarkAPIEventGenerator generator(ui_loop());

  generator.NewEvent<RemoveBookmarkFunction>(kTestExtensionPath1,
      new RemoveBookmarkFunction(), 1);
  generator.NewEvent<MoveBookmarkFunction>(kTestExtensionPath1,
      new MoveBookmarkFunction(), 1);
  generator.NewEvent<UpdateBookmarkFunction>(kTestExtensionPath1,
      new UpdateBookmarkFunction(), 2);
  generator.NewEvent<CreateBookmarkFunction>(kTestExtensionPath1,
      new CreateBookmarkFunction(), 3);
  generator.NewEvent<SearchBookmarksFunction>(kTestExtensionPath1,
      new SearchBookmarksFunction(), 5);
  const int writes_by_extension1 = 1 + 1 + 2 + 3;

  generator.NewEvent<RemoveTreeBookmarkFunction>(kTestExtensionPath2,
      new RemoveTreeBookmarkFunction(), 8);
  generator.NewEvent<GetBookmarkTreeFunction>(kTestExtensionPath2,
      new GetBookmarkTreeFunction(), 13);
  generator.NewEvent<GetBookmarkChildrenFunction>(kTestExtensionPath2,
      new GetBookmarkChildrenFunction(), 21);
  generator.NewEvent<GetBookmarksFunction>(kTestExtensionPath2,
      new GetBookmarksFunction(), 33);
  const int writes_by_extension2 = 8;

  ExtensionsActivityMonitor::Records results;
  monitor->GetAndClearRecords(&results);

  std::string id1 = GetExtensionIdForPath(kTestExtensionPath1);
  std::string id2 = GetExtensionIdForPath(kTestExtensionPath2);

  EXPECT_EQ(2, results.size());
  EXPECT_TRUE(results.end() != results.find(id1));
  EXPECT_TRUE(results.end() != results.find(id2));
  EXPECT_EQ(writes_by_extension1, results[id1].bookmark_write_count);
  EXPECT_EQ(writes_by_extension2, results[id2].bookmark_write_count);

  ui_loop()->DeleteSoon(FROM_HERE, monitor);
}

TEST_F(ExtensionsActivityMonitorTest, Put) {
  ExtensionsActivityMonitor* monitor = new ExtensionsActivityMonitor(ui_loop());
  BookmarkAPIEventGenerator generator(ui_loop());
  std::string id1 = GetExtensionIdForPath(kTestExtensionPath1);
  std::string id2 = GetExtensionIdForPath(kTestExtensionPath2);

  generator.NewEvent<CreateBookmarkFunction>(kTestExtensionPath1,
      new CreateBookmarkFunction(), 5);
  generator.NewEvent<MoveBookmarkFunction>(kTestExtensionPath2,
      new MoveBookmarkFunction(), 8);

  ExtensionsActivityMonitor::Records results;
  monitor->GetAndClearRecords(&results);

  EXPECT_EQ(2, results.size());
  EXPECT_EQ(5, results[id1].bookmark_write_count);
  EXPECT_EQ(8, results[id2].bookmark_write_count);

  generator.NewEvent<GetBookmarksFunction>(kTestExtensionPath2,
      new GetBookmarksFunction(), 3);
  generator.NewEvent<UpdateBookmarkFunction>(kTestExtensionPath2,
      new UpdateBookmarkFunction(), 2);

  // Simulate a commit failure, which augments the active record set with the
  // refugee records.
  monitor->PutRecords(results);
  ExtensionsActivityMonitor::Records new_records;
  monitor->GetAndClearRecords(&new_records);

  EXPECT_EQ(2, results.size());
  EXPECT_EQ(id1, new_records[id1].extension_id);
  EXPECT_EQ(id2, new_records[id2].extension_id);
  EXPECT_EQ(5, new_records[id1].bookmark_write_count);
  EXPECT_EQ(8 + 2, new_records[id2].bookmark_write_count);
  ui_loop()->DeleteSoon(FROM_HERE, monitor);
}

TEST_F(ExtensionsActivityMonitorTest, MultiGet) {
  ExtensionsActivityMonitor* monitor = new ExtensionsActivityMonitor(ui_loop());
  BookmarkAPIEventGenerator generator(ui_loop());
  std::string id1 = GetExtensionIdForPath(kTestExtensionPath1);

  generator.NewEvent<CreateBookmarkFunction>(kTestExtensionPath1,
      new CreateBookmarkFunction(), 5);

  ExtensionsActivityMonitor::Records results;
  monitor->GetAndClearRecords(&results);

  EXPECT_EQ(1, results.size());
  EXPECT_EQ(5, results[id1].bookmark_write_count);

  monitor->GetAndClearRecords(&results);
  EXPECT_TRUE(results.empty());

  generator.NewEvent<CreateBookmarkFunction>(kTestExtensionPath1,
      new CreateBookmarkFunction(), 3);
  monitor->GetAndClearRecords(&results);

  EXPECT_EQ(1, results.size());
  EXPECT_EQ(3, results[id1].bookmark_write_count);

  ui_loop()->DeleteSoon(FROM_HERE, monitor);
}<|endoftext|>