diff options
| author | Andrew Bell <andrew.bell.ia@gmail.com> | 2019-05-15 10:47:03 -0400 |
|---|---|---|
| committer | Andrew Bell <andrew.bell.ia@gmail.com> | 2019-05-15 10:47:03 -0400 |
| commit | 8f268409d37cea329d263e177b83e42f8384d3c7 (patch) | |
| tree | c4d0f3dd19456600f718a6e0c8573577f433549b /test | |
| parent | 886ced02f0aaab5d66d16459435f7447cf976650 (diff) | |
| parent | d67203a6f76a74f5ac029ff052dbcc72e3b59624 (diff) | |
| download | PROJ-8f268409d37cea329d263e177b83e42f8384d3c7.tar.gz PROJ-8f268409d37cea329d263e177b83e42f8384d3c7.zip | |
Merge remote-tracking branch 'origin/master'
Diffstat (limited to 'test')
66 files changed, 5593 insertions, 1410 deletions
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b618091b..ae721d46 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -17,7 +17,8 @@ proj_add_gie_test("GIGS-5101.1-jhs" "gigs/5101.1-jhs.gie") proj_add_gie_test("GIGS-5101.2-jhs" "gigs/5101.2-jhs.gie") proj_add_gie_test("GIGS-5101.3-jhs" "gigs/5101.3-jhs.gie") proj_add_gie_test("GIGS-5101.4-jhs-etmerc" "gigs/5101.4-jhs-etmerc.gie") -#proj_add_gie_test("GIGS-5101.4-jhs" "gigs/5101.4-jhs.gie") # Same as above, but using etmerc instead of tmerc +# Same as above, but using etmerc instead of tmerc +#proj_add_gie_test("GIGS-5101.4-jhs" "gigs/5101.4-jhs.gie") proj_add_gie_test("GIGS-5102.1" "gigs/5102.1.gie") #proj_add_gie_test("GIGS-5102.2" "gigs/5102.2.gie") proj_add_gie_test("GIGS-5103.1" "gigs/5103.1.gie") diff --git a/test/cli/CMakeLists.txt b/test/cli/CMakeLists.txt index 0c4ccf1b..4e1ab75a 100644 --- a/test/cli/CMakeLists.txt +++ b/test/cli/CMakeLists.txt @@ -5,11 +5,11 @@ set(CS2CS_BIN "cs2cs") set(PROJ_BIN "proj") set(PROJINFO_BIN "projinfo") set(CCT_BIN "cct") -proj_add_test_script_sh("test27" PROJ_BIN ) -proj_add_test_script_sh("test83" PROJ_BIN ) -proj_add_test_script_sh("testvarious" CS2CS_BIN ) +proj_add_test_script_sh("test27" PROJ_BIN) +proj_add_test_script_sh("test83" PROJ_BIN) +proj_add_test_script_sh("testvarious" CS2CS_BIN) proj_add_test_script_sh("testdatumfile" CS2CS_BIN "connu") proj_add_test_script_sh("testIGNF" CS2CS_BIN "ntf_r93.gsb") proj_add_test_script_sh("testntv2" CS2CS_BIN "ntv2_0.gsb") -proj_add_test_script_sh("testprojinfo" PROJINFO_BIN ) -proj_add_test_script_sh("testcct" CCT_BIN ) +proj_add_test_script_sh("testprojinfo" PROJINFO_BIN) +proj_add_test_script_sh("testcct" CCT_BIN) diff --git a/test/cli/Makefile.am b/test/cli/Makefile.am index c0bc0871..47cb1e7f 100644 --- a/test/cli/Makefile.am +++ b/test/cli/Makefile.am @@ -1,5 +1,5 @@ # Executables paths passed to test scripts -DATAPATH = ../../data +PROJ_LIB ?= ../../data THIS_DIR = $(top_srcdir)/test/cli EXEPATH = ../../src PROJEXE = $(EXEPATH)/proj @@ -27,7 +27,7 @@ EXTRA_DIST = pj_out27.dist pj_out83.dist td_out.dist \ CMakeLists.txt testprojinfo-check: - PROJ_LIB=$(DATAPATH) $(TESTPROJINFO) $(PROJINFOEXE) + PROJ_LIB=$(PROJ_LIB) $(TESTPROJINFO) $(PROJINFOEXE) test27-check: $(TEST27) $(PROJEXE) @@ -36,24 +36,24 @@ test83-check: $(TEST83) $(PROJEXE) testvarious-check: - PROJ_LIB=$(DATAPATH) $(TESTVARIOUS) $(CS2CSEXE) + PROJ_LIB=$(PROJ_LIB) $(TESTVARIOUS) $(CS2CSEXE) testdatumfile-check: - @if [ -f $(DATAPATH)/conus -a -f $(DATAPATH)/ntv1_can.dat -a -f $(DATAPATH)/MD -a -f $(DATAPATH)/ntf_r93.gsb ]; then \ - PROJ_LIB=$(DATAPATH) $(TESTDATUMFILE) $(CS2CSEXE) ; \ + @if [ -f $(PROJ_LIB)/conus -a -f $(PROJ_LIB)/ntv1_can.dat -a -f $(PROJ_LIB)/MD -a -f $(PROJ_LIB)/ntf_r93.gsb ]; then \ + PROJ_LIB=$(PROJ_LIB) $(TESTDATUMFILE) $(CS2CSEXE) ; \ fi testign-check: - @if [ -f $(DATAPATH)/ntf_r93.gsb ] ; then \ - PROJ_LIB=$(DATAPATH) $(TESTIGN) $(CS2CSEXE) ; \ + @if [ -f $(PROJ_LIB)/ntf_r93.gsb ] ; then \ + PROJ_LIB=$(PROJ_LIB) $(TESTIGN) $(CS2CSEXE) ; \ fi testntv2-check: - @if [ -f $(DATAPATH)/ntv2_0.gsb ] ; then \ - PROJ_LIB=$(DATAPATH) $(TESTNTV2) $(CS2CSEXE) ; \ + @if [ -f $(PROJ_LIB)/ntv2_0.gsb ] ; then \ + PROJ_LIB=$(PROJ_LIB) $(TESTNTV2) $(CS2CSEXE) ; \ fi testcct-check: - PROJ_LIB=$(DATAPATH) $(TESTCCT) $(CCTEXE) + PROJ_LIB=$(PROJ_LIB) $(TESTCCT) $(CCTEXE) check-local: testprojinfo-check test27-check test83-check testvarious-check testdatumfile-check testign-check testntv2-check testcct-check diff --git a/test/cli/test27 b/test/cli/test27 index 43c060d8..bfc1cb0a 100755 --- a/test/cli/test27 +++ b/test/cli/test27 @@ -7,7 +7,6 @@ # Mercator due to greater precision of meridional distance function. # TEST_CLI_DIR=`dirname $0` -DATA_DIR=`dirname $0`/../../data EXE=$1 usage() @@ -26,12 +25,16 @@ if test ! -x ${EXE}; then exit 1 fi +if test -z "${PROJ_LIB}"; then + export PROJ_LIB="`dirname $0`/../../data" +fi + echo "============================================" echo "Running ${0} using ${EXE}:" echo "============================================" OUT=proj_out27 -INIT_FILE=${DATA_DIR}/nad27 +INIT_FILE=${PROJ_LIB}/nad27 # echo "doing tests into file ${OUT}, please wait" # @@ -833,7 +836,7 @@ EOF # # do 'diff' with distribution results echo "diff ${OUT} with pj_out27.dist" -diff -b ${OUT} ${TEST_CLI_DIR}/pj_out27.dist +diff -u -b ${OUT} ${TEST_CLI_DIR}/pj_out27.dist if [ $? -ne 0 ] ; then echo "" echo "PROBLEMS HAVE OCCURRED" diff --git a/test/cli/test83 b/test/cli/test83 index 82b491a7..cfb1365e 100755 --- a/test/cli/test83 +++ b/test/cli/test83 @@ -8,7 +8,6 @@ # Mercator due to greater precision of meridional distance function. # TEST_CLI_DIR=`dirname $0` -DATA_DIR=`dirname $0`/../../data EXE=$1 usage() @@ -27,12 +26,16 @@ if test ! -x ${EXE}; then exit 1 fi +if test -z "${PROJ_LIB}"; then + export PROJ_LIB="`dirname $0`/../../data" +fi + echo "============================================" echo "Running ${0} using ${EXE}:" echo "============================================" OUT=proj_out83 -INIT_FILE=${DATA_DIR}/nad83 +INIT_FILE=${PROJ_LIB}/nad83 # echo "doing tests into file ${OUT}, please wait" # @@ -714,7 +717,7 @@ EOF # # do 'diff' with distribution results echo "diff ${OUT} with pj_out83.dist" -diff -b ${OUT} ${TEST_CLI_DIR}/pj_out83.dist +diff -u -b ${OUT} ${TEST_CLI_DIR}/pj_out83.dist if [ $? -ne 0 ] ; then echo "" echo "PROBLEMS HAVE OCCURRED" diff --git a/test/cli/testIGNF b/test/cli/testIGNF index 0fa04e84..aa8c3354 100755 --- a/test/cli/testIGNF +++ b/test/cli/testIGNF @@ -12,7 +12,6 @@ # the gsb grid is still ok TEST_CLI_DIR=`dirname $0` -DATA_DIR=`dirname $0`/../../data EXE=$1 usage() @@ -32,7 +31,7 @@ if test ! -x ${EXE}; then fi if test -z "${PROJ_LIB}"; then - export PROJ_LIB=${DATA_DIR} + export PROJ_LIB="`dirname $0`/../../data" fi echo "============================================" @@ -159,7 +158,7 @@ EOF # # do 'diff' with distribution results echo "diff ${OUT} with ${OUT}.dist" -diff -b ${OUT} ${TEST_CLI_DIR}/${OUT}.dist +diff -u -b ${OUT} ${TEST_CLI_DIR}/${OUT}.dist if [ $? -ne 0 ] ; then echo "" echo "PROBLEMS HAVE OCCURRED" diff --git a/test/cli/testcct b/test/cli/testcct index 93749052..3fb0dd95 100755 --- a/test/cli/testcct +++ b/test/cli/testcct @@ -2,7 +2,6 @@ # Test cct TEST_CLI_DIR=`dirname $0` -DATA_DIR=`dirname $0`/../../data EXE=$1 usage() diff --git a/test/cli/testdatumfile b/test/cli/testdatumfile index e8995150..5b56f077 100755 --- a/test/cli/testdatumfile +++ b/test/cli/testdatumfile @@ -4,7 +4,6 @@ # # TEST_CLI_DIR=`dirname $0` -DATA_DIR=`dirname $0`/../../data EXE=$1 usage() @@ -114,7 +113,7 @@ rm -rf "dir with \" space" # Done! # do 'diff' with distribution results echo "diff ${OUT} with ${OUT}.dist" -diff -b ${OUT} ${TEST_CLI_DIR}/${OUT}.dist +diff -u -b ${OUT} ${TEST_CLI_DIR}/${OUT}.dist if [ $? -ne 0 ] ; then echo "" echo "PROBLEMS HAVE OCCURRED" diff --git a/test/cli/testflaky b/test/cli/testflaky index af56a9cd..23580146 100755 --- a/test/cli/testflaky +++ b/test/cli/testflaky @@ -4,7 +4,6 @@ # # TEST_CLI_DIR=`dirname $0` -DATA_DIR=`dirname $0`/../../data EXE=$1 usage() @@ -59,7 +58,7 @@ EOF # Done! # do 'diff' with distribution results echo "diff ${OUT} with ${OUT}.dist" -diff -b ${OUT} ${TEST_CLI_DIR}/${OUT}.dist +diff -u -b ${OUT} ${TEST_CLI_DIR}/${OUT}.dist if [ $? -ne 0 ] ; then echo "" echo "PROBLEMS HAVE OCCURRED" diff --git a/test/cli/testntv2 b/test/cli/testntv2 index e82026fc..73371dbe 100755 --- a/test/cli/testntv2 +++ b/test/cli/testntv2 @@ -4,7 +4,6 @@ # # TEST_CLI_DIR=`dirname $0` -DATA_DIR=`dirname $0`/../../data EXE=$1 usage() @@ -58,7 +57,7 @@ EOF # Done! # do 'diff' with distribution results echo "diff ${OUT} with ${OUT}.dist" -diff -b ${OUT} ${TEST_CLI_DIR}/${OUT}.dist +diff -u -b ${OUT} ${TEST_CLI_DIR}/${OUT}.dist if [ $? -ne 0 ] ; then echo "" echo "PROBLEMS HAVE OCCURRED" diff --git a/test/cli/testprojinfo b/test/cli/testprojinfo index 111c071e..d8569a76 100755 --- a/test/cli/testprojinfo +++ b/test/cli/testprojinfo @@ -2,7 +2,6 @@ # Test projinfo TEST_CLI_DIR=`dirname $0` -DATA_DIR=`dirname $0`/../../data EXE=$1 usage() @@ -29,6 +28,8 @@ OUT=testprojinfo_out rm -f ${OUT} +export PROJINFO_NO_GRID_CHECK=YES + echo "Testing projinfo EPSG:4326" >> ${OUT} $EXE EPSG:4326 >>${OUT} echo "" >>${OUT} @@ -53,6 +54,10 @@ echo "Testing projinfo -s EPSG:4326 -t EPSG:32631" >> ${OUT} $EXE -s EPSG:4326 -t EPSG:32631 >>${OUT} echo "" >>${OUT} +echo "Testing projinfo -s NAD27 -t NAD83" >> ${OUT} +$EXE -s NAD27 -t NAD83 >>${OUT} +echo "" >>${OUT} + echo "Testing projinfo -s NAD27 -t NAD83 --grid-check none --spatial-test intersects --summary" >> ${OUT} $EXE -s NAD27 -t NAD83 --grid-check none --spatial-test intersects --summary >>${OUT} echo "" >>${OUT} @@ -98,6 +103,18 @@ echo "Testing CRS with towgs84: projinfo -o PROJ EPSG:25832" >> ${OUT} $EXE -o PROJ EPSG:25832 >>${OUT} 2>&1 echo "" >>${OUT} +echo "Testing RH2000 height to SWEREF99: projinfo -s EPSG:5613 -t EPSG:4977" >> ${OUT} +$EXE -s EPSG:5613 -t EPSG:4977 >>${OUT} 2>&1 +echo "" >>${OUT} + +echo "Testing NAD83(2011) + NAVD88 height -> NAD83(2011) : projinfo -s EPSG:6349 -t EPSG:6319 --spatial-test intersects -o PROJ" >> ${OUT} +$EXE -s EPSG:6349 -t EPSG:6319 --spatial-test intersects -o PROJ >>${OUT} 2>&1 +echo "" >>${OUT} + +echo "Testing NGF IGN69 height to RGF93: projinfo -s EPSG:5720 -t EPSG:4965 -o PROJ" >> ${OUT} +$EXE -s EPSG:5720 -t EPSG:4965 -o PROJ >>${OUT} 2>&1 +echo "" >>${OUT} + # do 'diff' with distribution results echo "diff ${OUT} with testprojinfo_out.dist" diff -u ${OUT} ${TEST_CLI_DIR}/testprojinfo_out.dist diff --git a/test/cli/testprojinfo_out.dist b/test/cli/testprojinfo_out.dist index ebc59c40..ea0f4983 100644 --- a/test/cli/testprojinfo_out.dist +++ b/test/cli/testprojinfo_out.dist @@ -136,6 +136,10 @@ GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.25722 Testing projinfo -s EPSG:4326 -t EPSG:32631 +Candidate operations found: 1 +------------------------------------- +Operation n°1: + EPSG:16031, UTM zone 31N, 0 m, World - N hemisphere - 0°E to 6°E PROJ string: @@ -162,17 +166,74 @@ CONVERSION["UTM zone 31N", ID["EPSG",8807]], ID["EPSG",16031]] +Testing projinfo -s NAD27 -t NAD83 +Candidate operations found: 1 +Note: using '--spatial-test intersects' would bring more results (7) +------------------------------------- +Operation n°1: + +unknown id, Ballpark geographic offset from NAD27 to NAD83, unknown accuracy, World, has ballpark transformation + +PROJ string: ++proj=noop + +WKT2_2018 string: +COORDINATEOPERATION["Ballpark geographic offset from NAD27 to NAD83", + SOURCECRS[ + GEOGCRS["NAD27", + DATUM["North American Datum 1927", + ELLIPSOID["Clarke 1866",6378206.4,294.978698213898, + LENGTHUNIT["metre",1]]], + PRIMEM["Greenwich",0, + ANGLEUNIT["degree",0.0174532925199433]], + CS[ellipsoidal,2], + AXIS["geodetic latitude (Lat)",north, + ORDER[1], + ANGLEUNIT["degree",0.0174532925199433]], + AXIS["geodetic longitude (Lon)",east, + ORDER[2], + ANGLEUNIT["degree",0.0174532925199433]], + ID["EPSG",4267]]], + TARGETCRS[ + GEOGCRS["NAD83", + DATUM["North American Datum 1983", + ELLIPSOID["GRS 1980",6378137,298.257222101, + LENGTHUNIT["metre",1]]], + PRIMEM["Greenwich",0, + ANGLEUNIT["degree",0.0174532925199433]], + CS[ellipsoidal,2], + AXIS["geodetic latitude (Lat)",north, + ORDER[1], + ANGLEUNIT["degree",0.0174532925199433]], + AXIS["geodetic longitude (Lon)",east, + ORDER[2], + ANGLEUNIT["degree",0.0174532925199433]], + ID["EPSG",4269]]], + METHOD["Geographic2D offsets", + ID["EPSG",9619]], + PARAMETER["Latitude offset",0, + ANGLEUNIT["degree",0.0174532925199433], + ID["EPSG",8601]], + PARAMETER["Longitude offset",0, + ANGLEUNIT["degree",0.0174532925199433], + ID["EPSG",8602]], + USAGE[ + SCOPE["unknown"], + AREA["World"], + BBOX[-90,-180,90,180]]] + Testing projinfo -s NAD27 -t NAD83 --grid-check none --spatial-test intersects --summary Candidate operations found: 7 DERIVED_FROM(EPSG):1312, NAD27 to NAD83 (3), 1.0 m, Canada DERIVED_FROM(EPSG):1313, NAD27 to NAD83 (4), 1.5 m, Canada - NAD27 DERIVED_FROM(EPSG):1241, NAD27 to NAD83 (1), 0.15 m, USA - CONUS including EEZ DERIVED_FROM(EPSG):1243, NAD27 to NAD83 (2), 0.5 m, USA - Alaska including EEZ -unknown id, Null geographic offset from NAD27 to NAD83, unknown accuracy, World EPSG:1462, NAD27 to NAD83 (5), 1.0 m, Canada - Quebec EPSG:1573, NAD27 to NAD83 (6), 1.5 m, Canada - Quebec +unknown id, Ballpark geographic offset from NAD27 to NAD83, unknown accuracy, World, has ballpark transformation Testing projinfo -s NAD27 -t NAD83 --grid-check none --spatial-test intersects +Candidate operations found: 7 ------------------------------------- Operation n°1: @@ -196,7 +257,8 @@ COORDINATEOPERATION["NAD27 to NAD83 (3)", ANGLEUNIT["degree",0.0174532925199433]], AXIS["geodetic longitude (Lon)",east, ORDER[2], - ANGLEUNIT["degree",0.0174532925199433]]]], + ANGLEUNIT["degree",0.0174532925199433]], + ID["EPSG",4267]]], TARGETCRS[ GEOGCRS["NAD83", DATUM["North American Datum 1983", @@ -210,7 +272,8 @@ COORDINATEOPERATION["NAD27 to NAD83 (3)", ANGLEUNIT["degree",0.0174532925199433]], AXIS["geodetic longitude (Lon)",east, ORDER[2], - ANGLEUNIT["degree",0.0174532925199433]]]], + ANGLEUNIT["degree",0.0174532925199433]], + ID["EPSG",4269]]], METHOD["NTv1", ID["EPSG",9614]], PARAMETERFILE["Latitude and longitude difference file","ntv1_can.dat"], @@ -244,7 +307,8 @@ COORDINATEOPERATION["NAD27 to NAD83 (4)", ANGLEUNIT["degree",0.0174532925199433]], AXIS["geodetic longitude (Lon)",east, ORDER[2], - ANGLEUNIT["degree",0.0174532925199433]]]], + ANGLEUNIT["degree",0.0174532925199433]], + ID["EPSG",4267]]], TARGETCRS[ GEOGCRS["NAD83", DATUM["North American Datum 1983", @@ -258,7 +322,8 @@ COORDINATEOPERATION["NAD27 to NAD83 (4)", ANGLEUNIT["degree",0.0174532925199433]], AXIS["geodetic longitude (Lon)",east, ORDER[2], - ANGLEUNIT["degree",0.0174532925199433]]]], + ANGLEUNIT["degree",0.0174532925199433]], + ID["EPSG",4269]]], METHOD["NTv2", ID["EPSG",9615]], PARAMETERFILE["Latitude and longitude difference file","ntv2_0.gsb"], @@ -292,7 +357,8 @@ COORDINATEOPERATION["NAD27 to NAD83 (1)", ANGLEUNIT["degree",0.0174532925199433]], AXIS["geodetic longitude (Lon)",east, ORDER[2], - ANGLEUNIT["degree",0.0174532925199433]]]], + ANGLEUNIT["degree",0.0174532925199433]], + ID["EPSG",4267]]], TARGETCRS[ GEOGCRS["NAD83", DATUM["North American Datum 1983", @@ -306,7 +372,8 @@ COORDINATEOPERATION["NAD27 to NAD83 (1)", ANGLEUNIT["degree",0.0174532925199433]], AXIS["geodetic longitude (Lon)",east, ORDER[2], - ANGLEUNIT["degree",0.0174532925199433]]]], + ANGLEUNIT["degree",0.0174532925199433]], + ID["EPSG",4269]]], METHOD["CTABLE2"], PARAMETERFILE["Latitude and longitude difference file","conus"], OPERATIONACCURACY[0.15], @@ -339,7 +406,8 @@ COORDINATEOPERATION["NAD27 to NAD83 (2)", ANGLEUNIT["degree",0.0174532925199433]], AXIS["geodetic longitude (Lon)",east, ORDER[2], - ANGLEUNIT["degree",0.0174532925199433]]]], + ANGLEUNIT["degree",0.0174532925199433]], + ID["EPSG",4267]]], TARGETCRS[ GEOGCRS["NAD83", DATUM["North American Datum 1983", @@ -353,7 +421,8 @@ COORDINATEOPERATION["NAD27 to NAD83 (2)", ANGLEUNIT["degree",0.0174532925199433]], AXIS["geodetic longitude (Lon)",east, ORDER[2], - ANGLEUNIT["degree",0.0174532925199433]]]], + ANGLEUNIT["degree",0.0174532925199433]], + ID["EPSG",4269]]], METHOD["CTABLE2"], PARAMETERFILE["Latitude and longitude difference file","alaska"], OPERATIONACCURACY[0.5], @@ -366,13 +435,14 @@ COORDINATEOPERATION["NAD27 to NAD83 (2)", ------------------------------------- Operation n°5: -unknown id, Null geographic offset from NAD27 to NAD83, unknown accuracy, World +EPSG:1462, NAD27 to NAD83 (5), 1.0 m, Canada - Quebec PROJ string: - ++proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GS2783v1.QUE +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1 WKT2_2018 string: -COORDINATEOPERATION["Null geographic offset from NAD27 to NAD83", +COORDINATEOPERATION["NAD27 to NAD83 (5)", + VERSION["SGQ-Can QC NT1"], SOURCECRS[ GEOGCRS["NAD27", DATUM["North American Datum 1927", @@ -387,10 +457,6 @@ COORDINATEOPERATION["Null geographic offset from NAD27 to NAD83", AXIS["geodetic longitude (Lon)",east, ORDER[2], ANGLEUNIT["degree",0.0174532925199433]], - USAGE[ - SCOPE["unknown"], - AREA["North America - NAD27"], - BBOX[7.15,167.65,83.17,-47.74]], ID["EPSG",4267]]], TARGETCRS[ GEOGCRS["NAD83", @@ -406,34 +472,28 @@ COORDINATEOPERATION["Null geographic offset from NAD27 to NAD83", AXIS["geodetic longitude (Lon)",east, ORDER[2], ANGLEUNIT["degree",0.0174532925199433]], - USAGE[ - SCOPE["unknown"], - AREA["North America - NAD83"], - BBOX[14.92,167.65,86.46,-47.74]], ID["EPSG",4269]]], - METHOD["Geographic2D offsets", - ID["EPSG",9619]], - PARAMETER["Latitude offset",0, - ANGLEUNIT["degree",0.0174532925199433], - ID["EPSG",8601]], - PARAMETER["Longitude offset",0, - ANGLEUNIT["degree",0.0174532925199433], - ID["EPSG",8602]], + METHOD["NTv1", + ID["EPSG",9614]], + PARAMETERFILE["Latitude and longitude difference file","GS2783v1.QUE"], + OPERATIONACCURACY[1.0], USAGE[ SCOPE["unknown"], - AREA["World"], - BBOX[-90,-180,90,180]]] + AREA["Canada - Quebec"], + BBOX[44.99,-79.85,62.62,-57.1]], + ID["EPSG",1462]] ------------------------------------- Operation n°6: -EPSG:1462, NAD27 to NAD83 (5), 1.0 m, Canada - Quebec +EPSG:1573, NAD27 to NAD83 (6), 1.5 m, Canada - Quebec PROJ string: -+proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GS2783v1.QUE +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1 ++proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=QUE27-83.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1 WKT2_2018 string: -COORDINATEOPERATION["NAD27 to NAD83 (5)", +COORDINATEOPERATION["NAD27 to NAD83 (6)", + VERSION["SGQ-Can QC NT2"], SOURCECRS[ GEOGCRS["NAD27", DATUM["North American Datum 1927", @@ -447,7 +507,8 @@ COORDINATEOPERATION["NAD27 to NAD83 (5)", ANGLEUNIT["degree",0.0174532925199433]], AXIS["geodetic longitude (Lon)",east, ORDER[2], - ANGLEUNIT["degree",0.0174532925199433]]]], + ANGLEUNIT["degree",0.0174532925199433]], + ID["EPSG",4267]]], TARGETCRS[ GEOGCRS["NAD83", DATUM["North American Datum 1983", @@ -461,27 +522,28 @@ COORDINATEOPERATION["NAD27 to NAD83 (5)", ANGLEUNIT["degree",0.0174532925199433]], AXIS["geodetic longitude (Lon)",east, ORDER[2], - ANGLEUNIT["degree",0.0174532925199433]]]], - METHOD["NTv1", - ID["EPSG",9614]], - PARAMETERFILE["Latitude and longitude difference file","GS2783v1.QUE"], - OPERATIONACCURACY[1.0], + ANGLEUNIT["degree",0.0174532925199433]], + ID["EPSG",4269]]], + METHOD["NTv2", + ID["EPSG",9615]], + PARAMETERFILE["Latitude and longitude difference file","QUE27-83.gsb"], + OPERATIONACCURACY[1.5], USAGE[ SCOPE["unknown"], AREA["Canada - Quebec"], BBOX[44.99,-79.85,62.62,-57.1]], - ID["EPSG",1462]] + ID["EPSG",1573]] ------------------------------------- Operation n°7: -EPSG:1573, NAD27 to NAD83 (6), 1.5 m, Canada - Quebec +unknown id, Ballpark geographic offset from NAD27 to NAD83, unknown accuracy, World, has ballpark transformation PROJ string: -+proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=QUE27-83.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1 ++proj=noop WKT2_2018 string: -COORDINATEOPERATION["NAD27 to NAD83 (6)", +COORDINATEOPERATION["Ballpark geographic offset from NAD27 to NAD83", SOURCECRS[ GEOGCRS["NAD27", DATUM["North American Datum 1927", @@ -495,7 +557,8 @@ COORDINATEOPERATION["NAD27 to NAD83 (6)", ANGLEUNIT["degree",0.0174532925199433]], AXIS["geodetic longitude (Lon)",east, ORDER[2], - ANGLEUNIT["degree",0.0174532925199433]]]], + ANGLEUNIT["degree",0.0174532925199433]], + ID["EPSG",4267]]], TARGETCRS[ GEOGCRS["NAD83", DATUM["North American Datum 1983", @@ -509,16 +572,20 @@ COORDINATEOPERATION["NAD27 to NAD83 (6)", ANGLEUNIT["degree",0.0174532925199433]], AXIS["geodetic longitude (Lon)",east, ORDER[2], - ANGLEUNIT["degree",0.0174532925199433]]]], - METHOD["NTv2", - ID["EPSG",9615]], - PARAMETERFILE["Latitude and longitude difference file","QUE27-83.gsb"], - OPERATIONACCURACY[1.5], + ANGLEUNIT["degree",0.0174532925199433]], + ID["EPSG",4269]]], + METHOD["Geographic2D offsets", + ID["EPSG",9619]], + PARAMETER["Latitude offset",0, + ANGLEUNIT["degree",0.0174532925199433], + ID["EPSG",8601]], + PARAMETER["Longitude offset",0, + ANGLEUNIT["degree",0.0174532925199433], + ID["EPSG",8602]], USAGE[ SCOPE["unknown"], - AREA["Canada - Quebec"], - BBOX[44.99,-79.85,62.62,-57.1]], - ID["EPSG",1573]] + AREA["World"], + BBOX[-90,-180,90,180]]] Testing projinfo -s EPSG:4230 -t EPSG:4258 --bbox 8,54.51,15.24,57.8 --summary Candidate operations found: 1 @@ -564,7 +631,8 @@ PROJCRS["Monte Mario (Rome) / Italy zone 1", ELLIPSOID["International 1924",6378388,297, LENGTHUNIT["metre",1]]], PRIMEM["Rome",12.4523333333333, - ANGLEUNIT["degree",0.0174532925199433]]], + ANGLEUNIT["degree",0.0174532925199433]], + ID["EPSG",4806]], CONVERSION["Italy zone 1", METHOD["Transverse Mercator", ID["EPSG",9807]], @@ -625,3 +693,93 @@ Testing CRS with towgs84: projinfo -o PROJ EPSG:25832 PROJ.4 string: +proj=utm +zone=32 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs +Testing RH2000 height to SWEREF99: projinfo -s EPSG:5613 -t EPSG:4977 +Candidate operations found: 1 +------------------------------------- +Operation n°1: + +PROJ:EPSG_5613_TO_EPSG_4977, RH2000 height to SWEREF99, unknown accuracy, Sweden - onshore + +PROJ string: ++proj=vgridshift +grids=SWEN17_RH2000.gtx +multiplier=1 + +WKT2_2018 string: +COORDINATEOPERATION["RH2000 height to SWEREF99", + SOURCECRS[ + VERTCRS["RH2000 height", + VDATUM["Rikets hojdsystem 2000"], + CS[vertical,1], + AXIS["gravity-related height (H)",up, + LENGTHUNIT["metre",1]], + ID["EPSG",5613]]], + TARGETCRS[ + GEOGCRS["SWEREF99", + DATUM["SWEREF99", + ELLIPSOID["GRS 1980",6378137,298.257222101, + LENGTHUNIT["metre",1]]], + PRIMEM["Greenwich",0, + ANGLEUNIT["degree",0.0174532925199433]], + CS[ellipsoidal,3], + AXIS["geodetic latitude (Lat)",north, + ORDER[1], + ANGLEUNIT["degree",0.0174532925199433]], + AXIS["geodetic longitude (Lon)",east, + ORDER[2], + ANGLEUNIT["degree",0.0174532925199433]], + AXIS["ellipsoidal height (h)",up, + ORDER[3], + LENGTHUNIT["metre",1]], + ID["EPSG",4977]]], + METHOD["GravityRelatedHeight to Geographic3D", + ID["PROJ","HEIGHT_TO_GEOGRAPHIC3D"]], + PARAMETERFILE["Geoid (height correction) model file","SWEN17_RH2000.gtx"], + USAGE[ + SCOPE["unknown"], + AREA["Sweden - onshore"], + BBOX[55.28,10.93,69.07,24.17]], + ID["PROJ","EPSG_5613_TO_EPSG_4977"]] + +Testing NAD83(2011) + NAVD88 height -> NAD83(2011) : projinfo -s EPSG:6349 -t EPSG:6319 --spatial-test intersects -o PROJ +Candidate operations found: 2 +------------------------------------- +Operation n°1: + +unknown id, Inverse of NAD83(2011) to NAVD88 height (1), 0.1 m, USA - CONUS - onshore + +PROJ string: ++proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=vgridshift +grids=g2012bu0.gtx +multiplier=1 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1 + +------------------------------------- +Operation n°2: + +unknown id, Inverse of NAD83(2011) to NAVD88 height (2), 0.2 m, USA - Alaska + +PROJ string: ++proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=vgridshift +grids=g2012ba0.gtx +multiplier=1 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1 + +Testing NGF IGN69 height to RGF93: projinfo -s EPSG:5720 -t EPSG:4965 -o PROJ +Candidate operations found: 3 +------------------------------------- +Operation n°1: + +INVERSE(DERIVED_FROM(EPSG)):8885, Inverse of RGF93 to NGF IGN69 height (3), 0.01 m, France - mainland onshore + +PROJ string: ++proj=vgridshift +grids=RAF18.gtx +multiplier=1 + +------------------------------------- +Operation n°2: + +INVERSE(DERIVED_FROM(EPSG)):8371, Inverse of RGF93 to NGF IGN69 height (2), 0.02 m, France - mainland onshore + +PROJ string: ++proj=vgridshift +grids=RAF09.gtx +multiplier=1 + +------------------------------------- +Operation n°3: + +INVERSE(EPSG):10000, Inverse of RGF93 to NGF IGN69 height (1), 0.5 m, France - mainland onshore + +PROJ string: ++proj=pipeline +step +inv +proj=vgridshift +grids=ggf97a.txt +multiplier=1 + diff --git a/test/cli/testvarious b/test/cli/testvarious index c1fa61df..2e2d854c 100755 --- a/test/cli/testvarious +++ b/test/cli/testvarious @@ -4,7 +4,6 @@ # # TEST_CLI_DIR=`dirname $0` -DATA_DIR=`dirname $0`/../../data EXE=$1 usage() @@ -24,7 +23,7 @@ if test ! -x ${EXE}; then fi if test -z "${PROJ_LIB}"; then - export PROJ_LIB=$DATA_DIR + export PROJ_LIB="`dirname $0`/../../data" fi # Would be great to have a universale way of selecting a locale with @@ -954,10 +953,33 @@ $EXE EPSG:32631 EPSG:4326 -E >> ${OUT} <<EOF EOF +echo "##############################################################" >> ${OUT} +echo "Test EPSG:4896 to EPSG:7930" >> ${OUT} +# Here we test that 4D coordinates are handled by cs2cs. Due to backwards +# compatibility, the t-component is not written to STDOUT as part of the +# coordinate data, but rather as part of the string that follows the xyz +# components. This is only seen by users when the -E option is used. Which +# means that this test also experience that behaviour. +$EXE -f %.4f EPSG:4896 EPSG:7930 -E >> ${OUT} <<EOF +3496737.2679 743254.4507 5264462.9620 2019.0 +3496737.2679 743254.4507 5264462.9620 2029.0 +EOF + + +echo "##############################################################" >> ${OUT} +echo "Test ITRF2000 to ITRF1993" >> ${OUT} +# Here we test that HUGE_VAL is passed as the time value if not explicitly +# specified +$EXE -f %.7f ITRF2000 ITRF1993 -E >> ${OUT} <<EOF +59.4967 -117.61748 329.396 +59.4967 -117.61748 329.396 1988 +EOF + + # Done! # do 'diff' with distribution results echo "diff ${OUT} with ${OUT}.dist" -diff -b ${OUT} ${TEST_CLI_DIR}/${OUT}.dist +diff -u -b ${OUT} ${TEST_CLI_DIR}/${OUT}.dist if [ $? -ne 0 ] ; then echo "" echo "PROBLEMS HAVE OCCURRED" diff --git a/test/cli/tv_out.dist b/test/cli/tv_out.dist index 257e9400..dcda5275 100644 --- a/test/cli/tv_out.dist +++ b/test/cli/tv_out.dist @@ -460,3 +460,11 @@ Test EPSG:4326 to EPSG:32631 ############################################################## Test EPSG:32631 to EPSG:4326 400000 5000000 0 45d8'47.014"N 1d43'40.681"E 0.000 +############################################################## +Test EPSG:4896 to EPSG:7930 +3496737.2679 743254.4507 5264462.9620 3496737.7857 743254.0394 5264462.6437 2019.0 +3496737.2679 743254.4507 5264462.9620 3496737.9401 743253.8861 5264462.5497 2029.0 +############################################################## +Test ITRF2000 to ITRF1993 +59.4967 -117.61748 329.396 59.4967002 -117.6174799 329.3845529 +59.4967 -117.61748 329.396 59.4967002 -117.6174799 329.3845529 1988 diff --git a/test/fuzzers/build_google_oss_fuzzers.sh b/test/fuzzers/build_google_oss_fuzzers.sh index 0cc618b9..cd9fed49 100755 --- a/test/fuzzers/build_google_oss_fuzzers.sh +++ b/test/fuzzers/build_google_oss_fuzzers.sh @@ -32,3 +32,10 @@ build_fuzzer() } build_fuzzer standard_fuzzer $(dirname $0)/standard_fuzzer.cpp +build_fuzzer proj_crs_to_crs_fuzzer $(dirname $0)/proj_crs_to_crs_fuzzer.cpp + +echo "[libfuzzer]" > $OUT/standard_fuzzer.options +echo "max_len = 10000" >> $OUT/standard_fuzzer.options + +echo "[libfuzzer]" > $OUT/proj_crs_to_crs_fuzzer.options +echo "max_len = 10000" >> $OUT/proj_crs_to_crs_fuzzer.options diff --git a/test/fuzzers/proj_crs_to_crs_fuzzer.cpp b/test/fuzzers/proj_crs_to_crs_fuzzer.cpp new file mode 100644 index 00000000..9b4b1ed9 --- /dev/null +++ b/test/fuzzers/proj_crs_to_crs_fuzzer.cpp @@ -0,0 +1,147 @@ +/****************************************************************************** + * + * Project: proj.4 + * Purpose: Fuzzer + * Author: Even Rouault, even.rouault at spatialys.com + * + ****************************************************************************** + * Copyright (c) 2017, Even Rouault <even.rouault at spatialys.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <sys/types.h> +#include <unistd.h> + +#include "proj_internal.h" // For pj_gc_unloadall() +#include "proj.h" + +/* Standalone build: +g++ -g -std=c++11 proj_crs_to_crs_fuzzer.cpp -o proj_crs_to_crs_fuzzer -fvisibility=hidden -DSTANDALONE ../../src/.libs/libproj.a -lpthread -lsqlite3 -I../../src -I../../include +*/ + +extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv); +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len); + +int LLVMFuzzerInitialize(int* /*argc*/, char*** argv) +{ + const char* argv0 = (*argv)[0]; + char* path = pj_strdup(argv0); + char* lastslash = strrchr(path, '/'); + if( lastslash ) + { + *lastslash = '\0'; + setenv("PROJ_LIB", path, 1); + } + else + { + setenv("PROJ_LIB", ".", 1); + } + free(path); + return 0; +} + +int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) +{ + if( len > 1000 ) + { +#ifdef STANDALONE + fprintf(stderr, "Input too large\n"); +#endif + return 0; + } + + /* We expect the blob to be 2 lines: */ + /* source_string\ndestination_string */ + char* buf_dup = (char*)malloc(len+1); + memcpy(buf_dup, buf, len); + buf_dup[len] = 0; + char* first_line = buf_dup; + char* first_newline = strchr(first_line, '\n'); + if( !first_newline ) + { + free(buf_dup); + return 0; + } + first_newline[0] = 0; + char* second_line = first_newline + 1; + +#ifdef STANDALONE + fprintf(stderr, "src=%s\n", first_line); + fprintf(stderr, "dst=%s\n", second_line); +#endif + + proj_destroy( + proj_create_crs_to_crs(nullptr, first_line, second_line, nullptr)); + + free(buf_dup); + pj_gc_unloadall(pj_get_default_ctx()); + pj_deallocate_grids(); + return 0; +} + +#ifdef STANDALONE + +int main(int argc, char* argv[]) +{ + if( argc < 2 ) + { + const char str[] = + "+proj=longlat +datum=WGS84 +nodefs\n+proj=longlat +datum=WGS84 +nodefs"; + int ret = LLVMFuzzerTestOneInput((const uint8_t*)(str), sizeof(str) - 1); + if( ret ) + return ret; + + return 0; + } + else + { + int nRet = 0; + void* buf = NULL; + int nLen = 0; + FILE* f = fopen(argv[1], "rb"); + if( !f ) + { + fprintf(stderr, "%s does not exist.\n", argv[1]); + exit(1); + } + fseek(f, 0, SEEK_END); + nLen = (int)ftell(f); + fseek(f, 0, SEEK_SET); + buf = malloc(nLen); + if( !buf ) + { + fprintf(stderr, "malloc failed.\n"); + fclose(f); + exit(1); + } + fread(buf, nLen, 1, f); + fclose(f); + nRet = LLVMFuzzerTestOneInput((const uint8_t*)(buf), nLen); + free(buf); + return nRet; + } +} + +#endif // STANDALONE diff --git a/test/fuzzers/standard_fuzzer.cpp b/test/fuzzers/standard_fuzzer.cpp index e1c3bbf3..11f8738e 100644 --- a/test/fuzzers/standard_fuzzer.cpp +++ b/test/fuzzers/standard_fuzzer.cpp @@ -64,6 +64,14 @@ int LLVMFuzzerInitialize(int* /*argc*/, char*** argv) int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) { + if( len > 1000 ) + { +#ifdef STANDALONE + fprintf(stderr, "Input too large\n"); +#endif + return 0; + } + /* We expect the blob to be 3 lines: */ /* source proj string\ndestination proj string\nx y */ char* buf_dup = (char*)malloc(len+1); diff --git a/test/gie/4D-API_cs2cs-style.gie b/test/gie/4D-API_cs2cs-style.gie index bcdc256f..19b3ad96 100644 --- a/test/gie/4D-API_cs2cs-style.gie +++ b/test/gie/4D-API_cs2cs-style.gie @@ -33,8 +33,9 @@ tolerance 1 um direction inverse -accept 3565285.00000000 855949.00000000 5201383.00000000 -expect 3565285.41342351 855948.67986759 5201382.72939791 +# Broken test. FIXME +#accept 3565285.00000000 855949.00000000 5201383.00000000 +#expect 3565285.41342351 855948.67986759 5201382.72939791 ------------------------------------------------------------------------------- @@ -107,11 +108,12 @@ operation proj=latlong geoidgrids=egm96_15.gtx axis=neu ellps=GRS80 ------------------------------------------------------------------------------- tolerance 15 cm # lax tolerance due to widely distributed, bad egm96 file ignore pjd_err_failed_to_load_grid -accept 12.5 55.5 0 -expect 55.5 12.5 -36.0213 -direction inverse -accept 55.5 12.5 -36.0213 -expect 12.5 55.5 0 +# Broken test. FIXME +#accept 12.5 55.5 0 +#expect 55.5 12.5 -36.0213 +#direction inverse +#accept 55.5 12.5 -36.0213 +#expect 12.5 55.5 0 ------------------------------------------------------------------------------- operation proj=latlong geoidgrids=egm96_15.gtx axis=dne ellps=GRS80 ------------------------------------------------------------------------------- @@ -142,8 +144,9 @@ operation proj=latlong geoidgrids=egm96_15.gtx axis=nue ellps=GRS80 ------------------------------------------------------------------------------- tolerance 15 cm # lax tolerance due to widely distributed, bad egm96 file ignore pjd_err_failed_to_load_grid -accept 12.5 55.5 0 -expect 55.5 -36.0213 12.5 +# Broken test. FIXME +#accept 12.5 55.5 0 +#expect 55.5 -36.0213 12.5 # direction inverse # accept 55.5 -36.0213 12.5 # expect 12.5 55.5 0 @@ -185,7 +188,7 @@ operation proj=pipeline k_0=1 x_0=2600000 y_0=1200000 ellps=bessel units=m ------------------------------------------------------------------------------- tolerance 20 cm -accept 7.438632495 46.951082877 +accept 7.438632495 46.951082877 0 expect 2600000.0 1200000.0 ------------------------------------------------------------------------------- @@ -465,4 +468,11 @@ accept 0 0 1000 expect 0 0 1 roundtrip 1 +------------------------------------------------------------------------------- +Check that proj_create() returns a generic error when an exception is caught +in the creation of a PJ object. +------------------------------------------------------------------------------- +operation this is a bogus CRS meant to trigger a generic error in proj_create() +expect failure errno generic error + </gie> diff --git a/test/gie/builtins.gie b/test/gie/builtins.gie index 37bdfc69..df19efb6 100644 --- a/test/gie/builtins.gie +++ b/test/gie/builtins.gie @@ -63,6 +63,19 @@ expect -0.001790494 0.000895246 accept -200 -100 expect -0.001790493 -0.000895247 +operation +proj=aea +ellps=GRS80 +lat_1=900 +expect failure errno lat_larger_than_90 + +operation +proj=aea +ellps=GRS80 +lat_2=900 +expect failure errno lat_larger_than_90 + +operation +proj=aea +R=6400000 +lat_1=1 +lat_2=-1 +expect failure errno conic_lat_equal + +------------------------------------------------------------------------------- +operation +proj=aea +a=9999999 +b=.9 +lat_2=1 +------------------------------------------------------------------------- +expect failure errno invalid_eccentricity =============================================================================== Azimuthal Equidistant @@ -311,7 +324,7 @@ Airy =============================================================================== ------------------------------------------------------------------------------- -operation +proj=airy +a=6400000 +lat_1=0 +lat_2=2 +operation +proj=airy +a=6400000 ------------------------------------------------------------------------------- tolerance 0.1 mm accept 2 1 @@ -391,6 +404,11 @@ expect 0 0 accept 25 25 expect 0.3821 0.4216 +------------------------------------------------------------------------------- +operation +proj=airy +R=1 +no_cut +------------------------------------------------------------------------------- +accept -180 0 +expect failure errno tolerance_condition =============================================================================== Aitoff @@ -608,7 +626,7 @@ Bonne (Werner lat_1=90) =============================================================================== ------------------------------------------------------------------------------- -operation +proj=bonne +ellps=GRS80 +lat_1=0.5 +lat_2=2 +operation +proj=bonne +ellps=GRS80 +lat_1=0.5 ------------------------------------------------------------------------------- tolerance 0.1 mm accept 2 1 @@ -631,7 +649,18 @@ accept -200 -100 expect -0.001796698 0.499095631 ------------------------------------------------------------------------------- -operation +proj=bonne +R=6400000 +lat_1=0.5 +lat_2=2 +operation +proj=bonne +ellps=GRS80 +lat_1=90 +------------------------------------------------------------------------------- +tolerance 0.1 mm +accept 0 90 +expect 0 0 + +direction inverse +accept 0 0 +expect 0 90 + +------------------------------------------------------------------------------- +operation +proj=bonne +R=6400000 +lat_1=0.5 ------------------------------------------------------------------------------- tolerance 0.1 mm accept 2 1 @@ -653,6 +682,16 @@ expect -0.001790562 0.500895246 accept -200 -100 expect -0.001790561 0.499104753 +------------------------------------------------------------------------------- +operation +proj=bonne +R=6400000 +lat_1=90 +------------------------------------------------------------------------------- +tolerance 0.1 mm +accept 0 90 +expect 0 0 + +direction inverse +accept 0 0 +expect 0 90 =============================================================================== Cal Coop Ocean Fish Invest Lines/Stations @@ -1270,6 +1309,17 @@ expect -0.001790221 0.000895246 accept -200 -100 expect -0.001790220 -0.000895247 +operation +proj=eqdc +a=9999999 +b=.9 +lat_2=1 +expect failure errno invalid_eccentricity + +operation +proj=eqdc +R=6400000 +lat_1=1 +lat_2=-1 +expect failure errno conic_lat_equal + +operation +proj=eqdc +R=6400000 +lat_1=91 +expect failure errno lat_larger_than_90 + +operation +proj=eqdc +R=6400000 +lat_2=91 +expect failure errno lat_larger_than_90 =============================================================================== Euler @@ -1513,14 +1563,8 @@ accept -2 -1 0 expect 6373287.27950247 -222560.09599219 -110568.77482092 direction inverse -accept 200 100 -expect 0.001796631 0.000898315 -accept 200 -100 -expect 0.001796631 -0.000898315 -accept -200 100 -expect -0.001796631 0.000898315 -accept -200 -100 -expect -0.001796631 -0.000898315 +accept 6373287.27950247 222560.09599219 110568.77482092 +expect 2 1 0 ------------------------------------------------------------------------------- operation +proj=geocent +a=6400000 +lat_1=0.5 +lat_2=2 @@ -1580,6 +1624,17 @@ expect -0.001790493 0.000895247 accept -200 -100 expect -0.001790493 -0.000895247 +------------------------------------------------------------------------------- +operation +proj=geos +R=1 +h=0 +------------------------------------------------------------------------------- +expect failure errno invalid_h + +------------------------------------------------------------------------------- +operation +proj=geos +R=1 +h=1e11 +------------------------------------------------------------------------------- +expect failure errno invalid_h + + =============================================================================== Ginsburg VIII (TsNIIGAiK) @@ -1809,6 +1864,10 @@ expect 4030931.833981509 1323687.864777399 accept -80.000000000 36.000000000 expect 3450764.261536101 -175619.041820732 +# For some reason, does not fail on MacOSX +#accept 60 -45 +#expect failure errno tolerance_condition + direction inverse accept -1800000.000000000 2600000.000000000 expect -157.989285000 64.851559610 @@ -1850,7 +1909,7 @@ Hammer & Eckert-Greifendorff =============================================================================== ------------------------------------------------------------------------------- -operation +proj=hammer +a=6400000 +lat_1=0.5 +lat_2=2 +operation +proj=hammer +a=6400000 ------------------------------------------------------------------------------- tolerance 0.1 mm accept 2 1 @@ -1873,6 +1932,12 @@ accept -200 -100 expect -0.001790493 -0.000895247 +------------------------------------------------------------------------------- +operation +proj=hammer +a=6400000 +W=1 +------------------------------------------------------------------------------- +accept -180 0 +expect failure errno tolerance_condition + =============================================================================== Hatano Asymmetrical Equal Area PCyl, Sph. @@ -2084,6 +2149,25 @@ expect -0.001796699 0.500904924 accept -200 -100 expect -0.001796698 0.499095076 +------------------------------------------------------------------------------- +operation +proj=imw_p +ellps=GRS80 +lat_1=0 +lat_2=10 +------------------------------------------------------------------------------- +tolerance 0.1 mm +accept 0 0 +expect 0 0 +accept 0.000000000000 0.000904928485 +expect 0 100 +accept 0.000898315284 0.000000000000 +expect 100 0 + +direction inverse +accept 0 0 +expect 0 0 +accept 0 100 +expect 0.000000000000 0.000904928485 +accept 100 0 +expect 0.000898315284 0.000000000000 + =============================================================================== Icosahedral Snyder Equal Area @@ -2091,7 +2175,7 @@ Icosahedral Snyder Equal Area =============================================================================== ------------------------------------------------------------------------------- -operation +proj=isea +a=6400000 +lat_1=0.5 +lat_2=2 +operation +proj=isea +a=6400000 ------------------------------------------------------------------------------- tolerance 0.1 mm accept 2 1 @@ -2103,6 +2187,9 @@ expect -1575486.353641554 3442168.342028188 accept -2 -1 expect -1575486.353880283 3234352.695594706 +operation +proj=isea +mode=hex +resolution=31 +accept 0 0 +expect failure =============================================================================== Kavraisky V @@ -2202,6 +2289,8 @@ accept -2 1 expect -3756305.328869175 -6478142.561571511 accept -2 -1 expect -3831703.658501982 -6759107.170155395 +accept 24.833333333333 59.757598563058 +expect 0 0 direction inverse accept 200 100 @@ -2212,7 +2301,13 @@ accept -200 100 expect 24.830447748 59.758403933 accept -200 -100 expect 24.830351182 59.756888426 +accept 0 0 +expect 24.833333333333 59.757598563058 +------------------------------------------------------------------------------- +operation +proj=krovak +lat_0=-90 +------------------------------------------------------------------------------- +expect failure errno invalid_arg =============================================================================== Laborde @@ -2446,6 +2541,11 @@ tolerance 10 cm accept 45 45 roundtrip 100 +------------------------------------------------------------------------------- +Test error in projection setup +------------------------------------------------------------------------------- +operation +proj=laea +ellps=GRS80 +lat_0=91 +expect failure errno lat_larger_than_90 =============================================================================== Lagrange @@ -2504,7 +2604,14 @@ direction inverse accept 2 0 0 expect failure errno tolerance_condition - +------------------------------------------------------------------------------- +operation +proj=lagrng +R=1 +------------------------------------------------------------------------------- +tolerance 0.1 mm +accept 0 89.9999999 +expect 0 2 +accept 0 -89.9999999 +expect 0 -2 =============================================================================== Larrivee @@ -2661,6 +2768,55 @@ direction inverse accept 131824.206082557 267239.875053699 expect 1 2 +------------------------------------------------------------------------------- +operation +proj=lcc +a=9999999 +b=.9 +lat_2=1 +------------------------------------------------------------------------------- +expect failure errno invalid_eccentricity + +------------------------------------------------------------------------------- +# This case is incredible. ossfuzz has found the exact value of lat_1 that +# triggers a division by zero +operation +proj=lcc +lat_1=2D32 +lat_2=0 +a=6378137 +b=0.2 +------------------------------------------------------------------------------- +expect failure +# For some reason fails on MacOSX with a different error +# errno invalid_eccentricity + +------------------------------------------------------------------------------- +operation +proj=lcc +ellps=GRS80 +lat_1=0 +lat_2=90 +------------------------------------------------------------------------------- +expect failure errno lat_1_or_2_zero_or_90 + +------------------------------------------------------------------------------- +operation +proj=lcc +ellps=GRS80 +lat_1=90 +lat_2=0 +------------------------------------------------------------------------------- +expect failure errno lat_1_or_2_zero_or_90 + +------------------------------------------------------------------------------- +operation +proj=lcc +ellps=GRS80 +lat_1=90 +lat_2=90 +------------------------------------------------------------------------------- +expect failure errno lat_1_or_2_zero_or_90 + +------------------------------------------------------------------------------- +operation +proj=lcc +ellps=sphere +lat_1=0 +lat_2=90 +------------------------------------------------------------------------------- +expect failure errno lat_1_or_2_zero_or_90 + +------------------------------------------------------------------------------- +operation +proj=lcc +ellps=sphere +lat_1=90 +lat_2=0 +------------------------------------------------------------------------------- +expect failure errno lat_1_or_2_zero_or_90 + +------------------------------------------------------------------------------- +operation +proj=lcc +ellps=sphere +lat_1=91 +------------------------------------------------------------------------------- +expect failure errno lat_larger_than_90 + +------------------------------------------------------------------------------- +operation +proj=lcc +ellps=sphere +lat_2=91 +------------------------------------------------------------------------------- +expect failure errno lat_larger_than_90 + =============================================================================== Lambert Conformal Conic Alternative Conic, Sph&Ell @@ -2809,7 +2965,7 @@ Space oblique for LANDSAT =============================================================================== ------------------------------------------------------------------------------- -operation +proj=lsat +ellps=GRS80 +lat_1=0.5 +lat_2=2 +lsat=1 +path=2 +operation +proj=lsat +ellps=GRS80 +lsat=1 +path=2 ------------------------------------------------------------------------------- tolerance 0.1 mm accept 2 1 @@ -2831,6 +2987,12 @@ expect 126.000734469 -0.001880155 accept -200 -100 expect 126.002524373 -0.001723782 +------------------------------------------------------------------------------- +operation +proj=lsat +path=1 +lsat=5 +ellps=sphere +------------------------------------------------------------------------------- +direction inverse +accept 0 1e10 +expect failure errno invalid_x_or_y =============================================================================== McBryde-Thomas Flat-Polar Sine (No. 1) @@ -3578,7 +3740,12 @@ roundtrip 100 ------------------------------------------------------------------------------- operation +proj=nsper +R=1 +h=0 ------------------------------------------------------------------------------- -expect failure errno h_less_than_zero +expect failure errno invalid_h + +------------------------------------------------------------------------------- +operation +proj=nsper +R=1 +h=1e11 +------------------------------------------------------------------------------- +expect failure errno invalid_h =============================================================================== @@ -3642,6 +3809,10 @@ expect -141.100733224 26.091712305 accept -200 -100 expect -65.862385599 51.830295078 +------------------------------------------------------------------------------- +operation +proj=ob_tran +R=6400000 +o_proj +o_proj=ob_tran +------------------------------------------------------------------------------- +expect failure errno pjd_err_failed_to_find_proj =============================================================================== Oblique Cylindrical Equal Area @@ -3672,6 +3843,85 @@ expect 179.999104753 -0.001790493 accept -200 -100 expect -179.999104753 -0.001790493 +Direction North +------------------------------------------------------------------------------- +operation +proj=ocea +a=6400000 +lat_1=45 +lat_2=45.0000001 +lon_1=0 +lon_2=0 +------------------------------------------------------------------------------- +tolerance 1 mm +accept 2 1 +expect 19994423.837934091687 223322.760576728586 + +------------------------------------------------------------------------------- +operation +proj=ocea +a=6400000 +lat_0=45 +alpha=0 +------------------------------------------------------------------------------- +tolerance 1 mm +accept 2 1 +expect 19994423.837934091687 223322.760576728586 + + +Direction South +------------------------------------------------------------------------------- +operation +proj=ocea +a=6400000 +lat_1=45 +lat_2=44.999999 +lon_1=0 +lon_2=0 +------------------------------------------------------------------------------- +tolerance 1 mm +accept 2 1 +expect 111769.145040585790 -223322.760576727480 + +------------------------------------------------------------------------------- +operation +proj=ocea +a=6400000 +lat_0=45 +alpha=180 +------------------------------------------------------------------------------- +tolerance 1 mm +accept 2 1 +expect 111769.145040585790 -223322.760576727480 + + +Direction East +------------------------------------------------------------------------------- +operation +proj=ocea +a=6400000 +lat_1=45 +lat_2=45 +lon_1=0 +lon_2=1e-8 +------------------------------------------------------------------------------- +tolerance 1 mm +accept 2 1 +expect 9742698.935838246718 4443057.188599349000 + +------------------------------------------------------------------------------- +operation +proj=ocea +a=6400000 +lat_0=45 +alpha=90 +------------------------------------------------------------------------------- +tolerance 1 mm +accept 2 1 +expect 9742698.935838246718 4443057.188599349000 + + +Direction West +------------------------------------------------------------------------------- +operation +proj=ocea +a=6400000 +lat_1=45 +lat_2=45 +lon_1=0 +lon_2=-1e-8 +------------------------------------------------------------------------------- +tolerance 1 mm +accept 2 1 +expect 10363494.047136424109 -4443057.188599349000 + +------------------------------------------------------------------------------- +operation +proj=ocea +a=6400000 +lat_0=45 +alpha=270 +------------------------------------------------------------------------------- +tolerance 1 mm +accept 2 1 +expect 10363494.047136424109 -4443057.188599349000 + + +Direction North-East +------------------------------------------------------------------------------- +operation +proj=ocea +a=6400000 +lat_1=45 +lat_2=45.00001 +lon_1=0 +lon_2=1e-5 +------------------------------------------------------------------------------- +# 3 mm needed for MacOSX... +tolerance 3 mm +accept 2 1 +expect 18596261.668446537107 2747542.17330662999 + +------------------------------------------------------------------------------- +operation +proj=ocea +a=6400000 +lat_0=45 +alpha=35.264383770917604 +------------------------------------------------------------------------------- +tolerance 1 mm +accept 2 1 +expect 18596261.668446537107 2747542.17330662999 =============================================================================== Oblated Equal Area @@ -3756,6 +4006,55 @@ expect 0.000898315 -0.001808739 accept -200 -100 expect -0.000898315 -0.001808739 +------------------------------------------------------------------------------- +operation +proj=omerc +R=1 +lat_0=1 +lat_1=2 +no_rot +------------------------------------------------------------------------------- +direction inverse +accept 0 1e200 +expect failure errno invalid_x_or_y + + + +Direction North-East +------------------------------------------------------------------------------- +operation +proj=omerc +a=6400000 +lat_0=45 +lat_1=45 +lat_2=45.00001 +lon_1=0 +lon_2=1e-5 +------------------------------------------------------------------------------- +tolerance 1 mm +accept 2 1 +expect -3569.825230822232 -5093592.310871849768 + +------------------------------------------------------------------------------- +operation +proj=omerc +a=6400000 +lat_0=45 +alpha=35.264383770917604 +------------------------------------------------------------------------------- +tolerance 1 mm +accept 2 1 +expect -3569.825230822232 -5093592.310871849768 + +------------------------------------------------------------------------------- +operation +proj=omerc +R=1 +alpha=0 +lat_0=90 +------------------------------------------------------------------------------- +expect failure errno lat_0_or_alpha_eq_90 + +------------------------------------------------------------------------------- +operation +proj=omerc +lat_1=0.1 +a=6400000 +b=1 +------------------------------------------------------------------------------- +expect failure errno invalid_eccentricity + +------------------------------------------------------------------------------- +operation +proj=omerc +lat_1=0.8 +a=6400000 +b=.4 +------------------------------------------------------------------------------- +expect failure errno invalid_eccentricity + +------------------------------------------------------------------------------- +operation +proj=omerc +lat_1=91 +------------------------------------------------------------------------------- +expect failure errno lat_larger_than_90 + +------------------------------------------------------------------------------- +operation +proj=omerc +lat_2=91 +------------------------------------------------------------------------------- +expect failure errno lat_larger_than_90 + =============================================================================== Ortelius Oval @@ -4438,7 +4737,7 @@ Robinson =============================================================================== ------------------------------------------------------------------------------- -operation +proj=robin +a=6400000 +lat_1=0.5 +lat_2=2 +operation +proj=robin +a=6400000 ------------------------------------------------------------------------------- tolerance 0.1 mm accept 2 1 @@ -4450,6 +4749,18 @@ expect -189588.423282508 107318.530350703 accept -2 -1 expect -189588.423282508 -107318.530350703 +accept 0 89.5 +expect 0.000000000000 8639799.718722090125 + +accept 0 90 +expect 0.000000000000 8654720.000000000000 + +accept 0 -89.5 +expect 0.000000000000 -8639799.718722090125 + +accept 0 -90 +expect 0.000000000000 -8654720.000000000000 + direction inverse accept 200 100 expect 0.002109689 0.000931806 @@ -4460,6 +4771,18 @@ expect -0.002109689 0.000931806 accept -200 -100 expect -0.002109689 -0.000931806 +accept 0.000000000000 8639799.718722090125 +expect 0 89.5 + +accept 0.000000000000 8654720.000000000000 +expect 0 90 + +accept 0.000000000000 -8639799.718722090125 +expect 0 -89.5 + +accept 0.000000000000 -8654720.000000000000 +expect 0 -90 + =============================================================================== Roussilhe Stereographic @@ -4674,7 +4997,7 @@ Oblique Stereographic Alternative =============================================================================== ------------------------------------------------------------------------------- -operation +proj=sterea +ellps=GRS80 +lat_1=0.5 +lat_2=2 +n=0.5 +operation +proj=sterea +ellps=GRS80 ------------------------------------------------------------------------------- tolerance 0.1 mm accept 2 1 @@ -4697,7 +5020,7 @@ accept -200 -100 expect -0.001796631 -0.000904369 ------------------------------------------------------------------------------- -operation +proj=sterea +R=6400000 +lat_1=0.5 +lat_2=2 +n=0.5 +operation +proj=sterea +R=6400000 ------------------------------------------------------------------------------- tolerance 0.1 mm accept 2 1 @@ -4708,6 +5031,8 @@ accept -2 1 expect -223407.810259507 111737.938996443 accept -2 -1 expect -223407.810259507 -111737.938996443 +accept 180 0 +expect failure errno tolerance_condition direction inverse accept 200 100 @@ -4719,6 +5044,61 @@ expect -0.001790493 0.000895247 accept -200 -100 expect -0.001790493 -0.000895247 +------------------------------------------------------------------------------- +operation +proj=sterea +ellps=GRS80 +lat_0=90 +------------------------------------------------------------------------------- +tolerance 0.1 mm +accept 0 90 +expect 0 0 +accept 0 89 +expect 0.000000000000 -111696.700323081997 +accept 0 45 +expect 0.000000000000 -5291160.727484324016 +accept 0 0 +expect 0.000000000000 -12713600.098641794175 + +------------------------------------------------------------------------------- +operation +proj=sterea +ellps=GRS80 +lat_0=89 +------------------------------------------------------------------------------- +tolerance 0.1 mm +accept 0 90 +expect 0.000000000000 111696.700314355621 +accept 0 89 +expect 0.000000000000 0 +accept 0 45 +expect 0.000000000000 -5160845.342319893651 +accept 0 0 +expect 0.000000000000 -12493602.143489977345 + +------------------------------------------------------------------------------- +operation +proj=sterea +ellps=GRS80 +lat_0=-90 +------------------------------------------------------------------------------- +tolerance 0.1 mm +accept 0 -90 +expect 0 0 +accept 0 -89 +expect 0.000000000000 111696.700323081997 +accept 0 -45 +expect 0.000000000000 5291160.727484324016 +accept 0 0 +expect 0.000000000000 12713600.098641794175 + +------------------------------------------------------------------------------- +operation +proj=sterea +ellps=GRS80 +lat_0=-89 +------------------------------------------------------------------------------- +tolerance 0.1 mm +accept 0 -90 +expect 0.000000000000 -111696.700314355621 +accept 0 -89 +expect 0.000000000000 0 +accept 0 -45 +expect 0.000000000000 5160845.342319893651 +accept 0 0 +expect 0.000000000000 12493602.143489977345 + + +operation +proj=sterea +a=9999 +b=.9 +lat_0=73 +expect failure =============================================================================== Gauss-Schreiber Transverse Mercator (aka Gauss-Laborde Reunion) @@ -4935,6 +5315,14 @@ expect -0.001790493 0.000895247 accept -200 -100 expect -0.001790493 -0.000895247 + +------------------------------------------------------------------------------- +operation +proj=tmerc +R=1 +------------------------------------------------------------------------------- +direction inverse +accept -1e200 0 +expect failure errno invalid_x_or_y + =============================================================================== Tobler-Mercator Cyl, Sph @@ -5009,9 +5397,9 @@ Two Point Equidistant =============================================================================== ------------------------------------------------------------------------------- -operation +proj=tpeqd +ellps=GRS80 +lat_1=0.5 +lat_2=2 +n=0.5 +operation +proj=tpeqd +ellps=GRS80 +lat_1=0.5 +lat_2=2 ------------------------------------------------------------------------------- -tolerance 0.15 mm +tolerance 0.18 mm accept 2 1 expect -27750.758831679 -222599.403691777 accept 2 -1 @@ -5032,7 +5420,7 @@ accept -200 -100 expect 0.000898554 1.248203369 ------------------------------------------------------------------------------- -operation +proj=tpeqd +a=6400000 +lat_1=0.5 +lat_2=2 +n=0.5 +operation +proj=tpeqd +a=6400000 +lat_1=0.5 +lat_2=2 ------------------------------------------------------------------------------- tolerance 0.1 mm accept 2 1 @@ -5054,6 +5442,10 @@ expect -0.000895485 1.248209507 accept -200 -100 expect 0.000895485 1.248209507 +------------------------------------------------------------------------------- +operation +proj=tpeqd +a=6400000 +lat_1=90 +lat_2=90 +lon_1=0 +lon_2=1 +------------------------------------------------------------------------------- +expect failure =============================================================================== Tilted perspective @@ -5083,6 +5475,8 @@ accept -200 100 expect -0.001376321 0.001453641 accept -200 -100 expect -0.001988706 -0.000228872 +accept 0 0 +expect 0 0 ------------------------------------------------------------------------------- operation +proj=tpers +a=6400000 +h=1000000 +tilt=20 @@ -5145,7 +5539,7 @@ Urmaev V =============================================================================== ------------------------------------------------------------------------------- -operation +proj=urm5 +a=6400000 +lat_1=0.5 +lat_2=2 +n=0.5 +operation +proj=urm5 +a=6400000 +n=0.5 ------------------------------------------------------------------------------- tolerance 0.1 mm accept 2 1 @@ -5157,6 +5551,8 @@ expect -223393.638433964 111696.818785117 accept -2 -1 expect -223393.638433964 -111696.818785117 +operation +proj=urm5 +a=6400000 +n=1 +alpha=90 +expect failure errno lat_0_or_alpha_eq_90 =============================================================================== Urmaev Flat-Polar Sinusoidal @@ -5257,6 +5653,13 @@ expect -0.001790494 0.000895247 accept -200 -100 expect -0.001790494 -0.000895247 +------------------------------------------------------------------------------- +operation +proj=vandg +R=1 +------------------------------------------------------------------------------- +direction inverse +accept 0 -1e100 +expect failure errno tolerance_condition + =============================================================================== van der Grinten II diff --git a/test/gie/ellipsoid.gie b/test/gie/ellipsoid.gie index ea7f3888..b84a512f 100644 --- a/test/gie/ellipsoid.gie +++ b/test/gie/ellipsoid.gie @@ -44,7 +44,7 @@ tolerance 10 nm accept 1 2 expect 111319.4907932736 221194.0771604237 -accept 12 55 +accept 12 55s expect 1335833.8895192828 7326837.7148738774 ------------------------------------------------------------------------------- @@ -67,6 +67,9 @@ expect failure errno major_axis_not_given operation proj=merc +R=0 expect failure errno major_axis_not_given +operation +proj=merc +R_a +a=2 +f=2 +expect failure errno major_axis_not_given + operation expect failure operation cobra @@ -131,11 +134,23 @@ Shape parameters operation proj=utm zone=32 ellps=GRS80 rf=0 expect failure errno rev_flattening_is_zero +operation proj=utm zone=32 ellps=GRS80 e=-0.5 +expect failure errno invalid_eccentricity + +operation proj=utm zone=32 ellps=GRS80 e=1 +expect failure errno invalid_eccentricity + operation proj=utm zone=32 ellps=GRS80 es=1 -expect failure errno eccentricity_is_one +expect failure errno invalid_eccentricity + +operation proj=utm zone=32 a=1 es=1.1 +expect failure errno invalid_eccentricity operation proj=utm zone=32 ellps=GRS80 b=0 -expect failure errno eccentricity_is_one +expect failure errno invalid_eccentricity + +operation proj=utm zone=32 ellps=GRS80 f=1 +expect failure errno invalid_eccentricity operation proj=utm zone=32 ellps=GRS80 b=6000000 accept 12 55 diff --git a/test/gie/more_builtins.gie b/test/gie/more_builtins.gie index d1c978a3..75ba55e9 100644 --- a/test/gie/more_builtins.gie +++ b/test/gie/more_builtins.gie @@ -253,6 +253,24 @@ ignore pjd_err_failed_to_load_grid accept 12.5 55.5 0 0 expect 12.5 55.5 -36.021305084228516 0 +accept -180.1 0 0 +expect -180.1 0 -21.2423 + +accept 179.9 0 0 +expect 179.9 0 -21.2423 + +accept 180 0 0 +expect 180 0 -21.1533 + +accept 540 0 0 +expect 540 0 -21.1533 + +accept -180 0 0 +expect -180 0 -21.1533 + +accept -540 0 0 +expect -540 0 -21.1533 + roundtrip 100 1 nm ------------------------------------------------------------------------------- Fail on purpose: +grids parameter is mandatory @@ -433,6 +451,11 @@ expect failure errno invalid_arg operation proj=helmert transpose expect failure errno invalid_arg +# Use of 2D Helmert interface with 3D Helmert setup +operation +proj=ob_tran +o_proj=helmert +o_lat_p=0 +direction inverse +accept 0 0 +expect failure errno 22 ------------------------------------------------------------------------------- Molodensky-Badekas from IOGP Guidance 7.2, Transformation from La Canoa to REGVEN @@ -751,4 +774,84 @@ expect 359 10 0 ------------------------------------------------------------------------------- +------------------------------------------------------------------------------- +# No-op +------------------------------------------------------------------------------- +operation +proj=noop +direction forward +accept 25 25 +expect 25 25 + +accept 25 25 25 +expect 25 25 25 + +accept 25 25 25 25 +expect 25 25 25 25 +------------------------------------------------------------------------------- + + +# Test invalid lat_0 +operation +proj=aeqd +R=1 +lat_0=91 +expect failure errno lat_larger_than_90 + +------------------------------------------------------------------------------- +# cart +------------------------------------------------------------------------------- + +operation +proj=cart +ellps=GRS80 +tolerance 0.001mm + +accept 0 0 0 +expect 6378137 0 0 + +accept 0 90 0 +expect 0 0 6356752.314140347 + +accept 0 -90 0 +expect 0 0 -6356752.314140347 + +accept 90 0 0 +expect 0 6378137 0 + +accept -90 0 0 +expect 0 -6378137 0 + +accept 180 0 0 +expect -6378137 0 0 + +accept -180 0 0 +expect -6378137 0 0 + +# Center of Earth ! +accept 0 0 -6378137 +expect 0 0 0 + +accept 0 90 -6356752.314140347 +expect 0 0 0 + +direction inverse + +accept 6378137 0 0 +expect 0 0 0 + +accept 0 0 6356752.314140347 +expect 0 90 0 + +accept 0 0 -6356752.314140347 +expect 0 -90 0 + +accept 0 6378137 0 +expect 90 0 0 + +accept 0 -6378137 0 +expect -90 0 0 + +accept -6378137 0 0 +expect 180 0 0 + +# Center of Earth ! +accept 0 0 0 +expect 0 0 -6378137 + + </gie> diff --git a/test/gie/unitconvert.gie b/test/gie/unitconvert.gie index 2e06fe72..f763959b 100644 --- a/test/gie/unitconvert.gie +++ b/test/gie/unitconvert.gie @@ -43,4 +43,28 @@ operation proj=unitconvert z_in=rad z_out=m accept 1 1 1 1 expect failure +operation proj=unitconvert xy_in=0 +expect failure + +operation proj=unitconvert xy_out=0 +expect failure + +operation proj=unitconvert xy_in=1e400 +expect failure + +operation proj=unitconvert xy_out=1e400 +expect failure + +operation proj=unitconvert z_in=0 +expect failure + +operation proj=unitconvert z_out=0 +expect failure + +operation proj=unitconvert z_in=1e400 +expect failure + +operation proj=unitconvert z_out=1e400 +expect failure + </gie> diff --git a/test/googletest/include/gtest/gtest-death-test.h b/test/googletest/include/gtest/gtest-death-test.h index 957a69c6..20c54d86 100644 --- a/test/googletest/include/gtest/gtest-death-test.h +++ b/test/googletest/include/gtest/gtest-death-test.h @@ -26,14 +26,14 @@ // 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. + // -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file defines the public API for death tests. It is // #included by gtest.h so a user doesn't need to include this // directly. +// GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ @@ -99,10 +99,11 @@ GTEST_API_ bool InDeathTestChild(); // // On the regular expressions used in death tests: // +// GOOGLETEST_CM0005 DO NOT DELETE // On POSIX-compliant systems (*nix), we use the <regex.h> library, // which uses the POSIX extended regex syntax. // -// On other platforms (e.g. Windows), we only support a simple regex +// On other platforms (e.g. Windows or Mac), we only support a simple regex // syntax implemented as part of Google Test. This limited // implementation should be enough most of the time when writing // death tests; though it lacks many features you can find in PCRE @@ -160,7 +161,7 @@ GTEST_API_ bool InDeathTestChild(); // is rarely a problem as people usually don't put the test binary // directory in PATH. // -// TODO(wan@google.com): make thread-safe death tests search the PATH. +// FIXME: make thread-safe death tests search the PATH. // Asserts that a given statement causes the program to exit, with an // integer exit status that satisfies predicate, and emitting error output @@ -198,9 +199,10 @@ class GTEST_API_ ExitedWithCode { const int exit_code_; }; -# if !GTEST_OS_WINDOWS +# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // Tests that an exit code describes an exit due to termination by a // given signal. +// GOOGLETEST_CM0006 DO NOT DELETE class GTEST_API_ KilledBySignal { public: explicit KilledBySignal(int signum); @@ -272,6 +274,54 @@ class GTEST_API_ KilledBySignal { # endif // NDEBUG for EXPECT_DEBUG_DEATH #endif // GTEST_HAS_DEATH_TEST +// This macro is used for implementing macros such as +// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where +// death tests are not supported. Those macros must compile on such systems +// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on +// systems that support death tests. This allows one to write such a macro +// on a system that does not support death tests and be sure that it will +// compile on a death-test supporting system. It is exposed publicly so that +// systems that have death-tests with stricter requirements than +// GTEST_HAS_DEATH_TEST can write their own equivalent of +// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED. +// +// Parameters: +// statement - A statement that a macro such as EXPECT_DEATH would test +// for program termination. This macro has to make sure this +// statement is compiled but not executed, to ensure that +// EXPECT_DEATH_IF_SUPPORTED compiles with a certain +// parameter iff EXPECT_DEATH compiles with it. +// regex - A regex that a macro such as EXPECT_DEATH would use to test +// the output of statement. This parameter has to be +// compiled but not evaluated by this macro, to ensure that +// this macro only accepts expressions that a macro such as +// EXPECT_DEATH would accept. +// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED +// and a return statement for ASSERT_DEATH_IF_SUPPORTED. +// This ensures that ASSERT_DEATH_IF_SUPPORTED will not +// compile inside functions where ASSERT_DEATH doesn't +// compile. +// +// The branch that has an always false condition is used to ensure that +// statement and regex are compiled (and thus syntactically correct) but +// never executed. The unreachable code macro protects the terminator +// statement from generating an 'unreachable code' warning in case +// statement unconditionally returns or throws. The Message constructor at +// the end allows the syntax of streaming additional messages into the +// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH. +# define GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, terminator) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + GTEST_LOG_(WARNING) \ + << "Death tests are not supported on this platform.\n" \ + << "Statement '" #statement "' cannot be verified."; \ + } else if (::testing::internal::AlwaysFalse()) { \ + ::testing::internal::RE::PartialMatch(".*", (regex)); \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + terminator; \ + } else \ + ::testing::Message() + // EXPECT_DEATH_IF_SUPPORTED(statement, regex) and // ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if // death tests are supported; otherwise they just issue a warning. This is @@ -284,9 +334,9 @@ class GTEST_API_ KilledBySignal { ASSERT_DEATH(statement, regex) #else # define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ - GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, ) + GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, ) # define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ - GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return) + GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, return) #endif } // namespace testing diff --git a/test/googletest/include/gtest/gtest-message.h b/test/googletest/include/gtest/gtest-message.h index fe879bca..5ca04161 100644 --- a/test/googletest/include/gtest/gtest-message.h +++ b/test/googletest/include/gtest/gtest-message.h @@ -26,10 +26,9 @@ // 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. + // -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file defines the Message class. // @@ -43,6 +42,8 @@ // to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user // program! +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ #define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ @@ -50,6 +51,9 @@ #include "gtest/internal/gtest-port.h" +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + // Ensures that there is at least one operator<< in the global namespace. // See Message& operator<<(...) below for why. void operator<<(const testing::internal::Secret&, int); @@ -196,7 +200,6 @@ class GTEST_API_ Message { std::string GetString() const; private: - #if GTEST_OS_SYMBIAN // These are needed as the Nokia Symbian Compiler cannot decide between // const T& and const T* in a function template. The Nokia compiler _can_ @@ -247,4 +250,6 @@ std::string StreamableToString(const T& streamable) { } // namespace internal } // namespace testing +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + #endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ diff --git a/test/googletest/include/gtest/gtest-param-test.h b/test/googletest/include/gtest/gtest-param-test.h index 038f9ba7..3e95e439 100644 --- a/test/googletest/include/gtest/gtest-param-test.h +++ b/test/googletest/include/gtest/gtest-param-test.h @@ -31,13 +31,12 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: vladl@google.com (Vlad Losev) -// // Macros and functions for implementing parameterized tests -// in Google C++ Testing Framework (Google Test) +// in Google C++ Testing and Mocking Framework (Google Test) // // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // +// GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ @@ -79,7 +78,7 @@ TEST_P(FooTest, HasBlahBlah) { // Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test // case with any set of parameters you want. Google Test defines a number // of functions for generating test parameters. They return what we call -// (surprise!) parameter generators. Here is a summary of them, which +// (surprise!) parameter generators. Here is a summary of them, which // are all in the testing namespace: // // @@ -185,15 +184,10 @@ TEST_P(DerivedTest, DoesBlah) { # include <utility> #endif -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-param-util.h" #include "gtest/internal/gtest-param-util-generated.h" -#if GTEST_HAS_PARAM_TEST - namespace testing { // Functions producing parameter generators. @@ -273,7 +267,7 @@ internal::ParamGenerator<T> Range(T start, T end) { // each with C-string values of "foo", "bar", and "baz": // // const char* strings[] = {"foo", "bar", "baz"}; -// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); +// INSTANTIATE_TEST_CASE_P(StringSequence, StringTest, ValuesIn(strings)); // // This instantiates tests from test case StlStringTest // each with STL strings with values "a" and "b": @@ -1375,8 +1369,6 @@ internal::CartesianProductHolder10<Generator1, Generator2, Generator3, } # endif // GTEST_HAS_COMBINE - - # define TEST_P(test_case_name, test_name) \ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ : public test_case_name { \ @@ -1390,8 +1382,8 @@ internal::CartesianProductHolder10<Generator1, Generator2, Generator3, #test_case_name, \ ::testing::internal::CodeLocation(\ __FILE__, __LINE__))->AddTestPattern(\ - #test_case_name, \ - #test_name, \ + GTEST_STRINGIFY_(test_case_name), \ + GTEST_STRINGIFY_(test_name), \ new ::testing::internal::TestMetaFactory< \ GTEST_TEST_CLASS_NAME_(\ test_case_name, test_name)>()); \ @@ -1412,21 +1404,21 @@ internal::CartesianProductHolder10<Generator1, Generator2, Generator3, // type testing::TestParamInfo<class ParamType>, and return std::string. // // testing::PrintToStringParamName is a builtin test suffix generator that -// returns the value of testing::PrintToString(GetParam()). It does not work -// for std::string or C strings. +// returns the value of testing::PrintToString(GetParam()). // // Note: test names must be non-empty, unique, and may only contain ASCII -// alphanumeric characters or underscore. +// alphanumeric characters or underscore. Because PrintToString adds quotes +// to std::string and C strings, it won't work for these types. # define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator, ...) \ - ::testing::internal::ParamGenerator<test_case_name::ParamType> \ + static ::testing::internal::ParamGenerator<test_case_name::ParamType> \ gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ - ::std::string gtest_##prefix##test_case_name##_EvalGenerateName_( \ + static ::std::string gtest_##prefix##test_case_name##_EvalGenerateName_( \ const ::testing::TestParamInfo<test_case_name::ParamType>& info) { \ return ::testing::internal::GetParamNameGen<test_case_name::ParamType> \ (__VA_ARGS__)(info); \ } \ - int gtest_##prefix##test_case_name##_dummy_ GTEST_ATTRIBUTE_UNUSED_ = \ + static int gtest_##prefix##test_case_name##_dummy_ GTEST_ATTRIBUTE_UNUSED_ = \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder<test_case_name>(\ #test_case_name, \ @@ -1439,6 +1431,4 @@ internal::CartesianProductHolder10<Generator1, Generator2, Generator3, } // namespace testing -#endif // GTEST_HAS_PARAM_TEST - #endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ diff --git a/test/googletest/include/gtest/gtest-param-test.h.pump b/test/googletest/include/gtest/gtest-param-test.h.pump index 3078d6d2..274f2b3b 100644 --- a/test/googletest/include/gtest/gtest-param-test.h.pump +++ b/test/googletest/include/gtest/gtest-param-test.h.pump @@ -30,13 +30,12 @@ $var maxtuple = 10 $$ Maximum number of Combine arguments we want to support. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: vladl@google.com (Vlad Losev) -// // Macros and functions for implementing parameterized tests -// in Google C++ Testing Framework (Google Test) +// in Google C++ Testing and Mocking Framework (Google Test) // // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // +// GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ @@ -78,7 +77,7 @@ TEST_P(FooTest, HasBlahBlah) { // Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test // case with any set of parameters you want. Google Test defines a number // of functions for generating test parameters. They return what we call -// (surprise!) parameter generators. Here is a summary of them, which +// (surprise!) parameter generators. Here is a summary of them, which // are all in the testing namespace: // // @@ -184,15 +183,10 @@ TEST_P(DerivedTest, DoesBlah) { # include <utility> #endif -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-param-util.h" #include "gtest/internal/gtest-param-util-generated.h" -#if GTEST_HAS_PARAM_TEST - namespace testing { // Functions producing parameter generators. @@ -272,7 +266,7 @@ internal::ParamGenerator<T> Range(T start, T end) { // each with C-string values of "foo", "bar", and "baz": // // const char* strings[] = {"foo", "bar", "baz"}; -// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); +// INSTANTIATE_TEST_CASE_P(StringSequence, StringTest, ValuesIn(strings)); // // This instantiates tests from test case StlStringTest // each with STL strings with values "a" and "b": @@ -441,8 +435,6 @@ internal::CartesianProductHolder$i<$for j, [[Generator$j]]> Combine( ]] # endif // GTEST_HAS_COMBINE - - # define TEST_P(test_case_name, test_name) \ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ : public test_case_name { \ @@ -456,8 +448,8 @@ internal::CartesianProductHolder$i<$for j, [[Generator$j]]> Combine( #test_case_name, \ ::testing::internal::CodeLocation(\ __FILE__, __LINE__))->AddTestPattern(\ - #test_case_name, \ - #test_name, \ + GTEST_STRINGIFY_(test_case_name), \ + GTEST_STRINGIFY_(test_name), \ new ::testing::internal::TestMetaFactory< \ GTEST_TEST_CLASS_NAME_(\ test_case_name, test_name)>()); \ @@ -485,14 +477,14 @@ internal::CartesianProductHolder$i<$for j, [[Generator$j]]> Combine( // to std::string and C strings, it won't work for these types. # define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator, ...) \ - ::testing::internal::ParamGenerator<test_case_name::ParamType> \ + static ::testing::internal::ParamGenerator<test_case_name::ParamType> \ gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ - ::std::string gtest_##prefix##test_case_name##_EvalGenerateName_( \ + static ::std::string gtest_##prefix##test_case_name##_EvalGenerateName_( \ const ::testing::TestParamInfo<test_case_name::ParamType>& info) { \ return ::testing::internal::GetParamNameGen<test_case_name::ParamType> \ (__VA_ARGS__)(info); \ } \ - int gtest_##prefix##test_case_name##_dummy_ GTEST_ATTRIBUTE_UNUSED_ = \ + static int gtest_##prefix##test_case_name##_dummy_ GTEST_ATTRIBUTE_UNUSED_ = \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder<test_case_name>(\ #test_case_name, \ @@ -505,6 +497,4 @@ internal::CartesianProductHolder$i<$for j, [[Generator$j]]> Combine( } // namespace testing -#endif // GTEST_HAS_PARAM_TEST - #endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ diff --git a/test/googletest/include/gtest/gtest-printers.h b/test/googletest/include/gtest/gtest-printers.h index 8a33164c..51865f84 100644 --- a/test/googletest/include/gtest/gtest-printers.h +++ b/test/googletest/include/gtest/gtest-printers.h @@ -26,10 +26,9 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) -// Google Test - The Google C++ Testing Framework + +// Google Test - The Google C++ Testing and Mocking Framework // // This file implements a universal value printer that can print a // value of any type T: @@ -46,6 +45,10 @@ // 2. operator<<(ostream&, const T&) defined in either foo or the // global namespace. // +// However if T is an STL-style container then it is printed element-wise +// unless foo::PrintTo(const T&, ostream*) is defined. Note that +// operator<<() is ignored for container types. +// // If none of the above is defined, it will print the debug string of // the value if it is a protocol buffer, or print the raw bytes in the // value otherwise. @@ -92,6 +95,8 @@ // being defined as many user-defined container types don't have // value_type. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ #define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ @@ -107,6 +112,12 @@ # include <tuple> #endif +#if GTEST_HAS_ABSL +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "absl/types/variant.h" +#endif // GTEST_HAS_ABSL + namespace testing { // Definitions in the 'internal' and 'internal2' name spaces are @@ -125,7 +136,11 @@ enum TypeKind { kProtobuf, // a protobuf type kConvertibleToInteger, // a type implicitly convertible to BiggestInt // (e.g. a named or unnamed enum type) - kOtherType // anything else +#if GTEST_HAS_ABSL + kConvertibleToStringView, // a type implicitly convertible to + // absl::string_view +#endif + kOtherType // anything else }; // TypeWithoutFormatter<T, kTypeKind>::PrintValue(value, os) is called @@ -137,7 +152,8 @@ class TypeWithoutFormatter { public: // This default version is called when kTypeKind is kOtherType. static void PrintValue(const T& value, ::std::ostream* os) { - PrintBytesInObjectTo(reinterpret_cast<const unsigned char*>(&value), + PrintBytesInObjectTo(static_cast<const unsigned char*>( + reinterpret_cast<const void*>(&value)), sizeof(value), os); } }; @@ -151,10 +167,10 @@ template <typename T> class TypeWithoutFormatter<T, kProtobuf> { public: static void PrintValue(const T& value, ::std::ostream* os) { - const ::testing::internal::string short_str = value.ShortDebugString(); - const ::testing::internal::string pretty_str = - short_str.length() <= kProtobufOneLinerMaxLength ? - short_str : ("\n" + value.DebugString()); + std::string pretty_str = value.ShortDebugString(); + if (pretty_str.length() > kProtobufOneLinerMaxLength) { + pretty_str = "\n" + value.DebugString(); + } *os << ("<" + pretty_str + ">"); } }; @@ -175,6 +191,19 @@ class TypeWithoutFormatter<T, kConvertibleToInteger> { } }; +#if GTEST_HAS_ABSL +template <typename T> +class TypeWithoutFormatter<T, kConvertibleToStringView> { + public: + // Since T has neither operator<< nor PrintTo() but can be implicitly + // converted to absl::string_view, we print it as a absl::string_view. + // + // Note: the implementation is further below, as it depends on + // internal::PrintTo symbol which is defined later in the file. + static void PrintValue(const T& value, ::std::ostream* os); +}; +#endif + // Prints the given value to the given ostream. If the value is a // protocol message, its debug string is printed; if it's an enum or // of a type implicitly convertible to BiggestInt, it's printed as an @@ -202,10 +231,19 @@ class TypeWithoutFormatter<T, kConvertibleToInteger> { template <typename Char, typename CharTraits, typename T> ::std::basic_ostream<Char, CharTraits>& operator<<( ::std::basic_ostream<Char, CharTraits>& os, const T& x) { - TypeWithoutFormatter<T, - (internal::IsAProtocolMessage<T>::value ? kProtobuf : - internal::ImplicitlyConvertible<const T&, internal::BiggestInt>::value ? - kConvertibleToInteger : kOtherType)>::PrintValue(x, &os); + TypeWithoutFormatter<T, (internal::IsAProtocolMessage<T>::value + ? kProtobuf + : internal::ImplicitlyConvertible< + const T&, internal::BiggestInt>::value + ? kConvertibleToInteger + : +#if GTEST_HAS_ABSL + internal::ImplicitlyConvertible< + const T&, absl::string_view>::value + ? kConvertibleToStringView + : +#endif + kOtherType)>::PrintValue(x, &os); return os; } @@ -364,11 +402,18 @@ class UniversalPrinter; template <typename T> void UniversalPrint(const T& value, ::std::ostream* os); +enum DefaultPrinterType { + kPrintContainer, + kPrintPointer, + kPrintFunctionPointer, + kPrintOther, +}; +template <DefaultPrinterType type> struct WrapPrinterType {}; + // Used to print an STL-style container when the user doesn't define // a PrintTo() for it. template <typename C> -void DefaultPrintTo(IsContainer /* dummy */, - false_type /* is not a pointer */, +void DefaultPrintTo(WrapPrinterType<kPrintContainer> /* dummy */, const C& container, ::std::ostream* os) { const size_t kMaxCount = 32; // The maximum number of elements to print. *os << '{'; @@ -401,40 +446,34 @@ void DefaultPrintTo(IsContainer /* dummy */, // implementation-defined. Therefore they will be printed as raw // bytes.) template <typename T> -void DefaultPrintTo(IsNotContainer /* dummy */, - true_type /* is a pointer */, +void DefaultPrintTo(WrapPrinterType<kPrintPointer> /* dummy */, T* p, ::std::ostream* os) { if (p == NULL) { *os << "NULL"; } else { - // C++ doesn't allow casting from a function pointer to any object - // pointer. - // - // IsTrue() silences warnings: "Condition is always true", - // "unreachable code". - if (IsTrue(ImplicitlyConvertible<T*, const void*>::value)) { - // T is not a function type. We just call << to print p, - // relying on ADL to pick up user-defined << for their pointer - // types, if any. - *os << p; - } else { - // T is a function type, so '*os << p' doesn't do what we want - // (it just prints p as bool). We want to print p as a const - // void*. However, we cannot cast it to const void* directly, - // even using reinterpret_cast, as earlier versions of gcc - // (e.g. 3.4.5) cannot compile the cast when p is a function - // pointer. Casting to UInt64 first solves the problem. - *os << reinterpret_cast<const void*>( - reinterpret_cast<internal::UInt64>(p)); - } + // T is not a function type. We just call << to print p, + // relying on ADL to pick up user-defined << for their pointer + // types, if any. + *os << p; + } +} +template <typename T> +void DefaultPrintTo(WrapPrinterType<kPrintFunctionPointer> /* dummy */, + T* p, ::std::ostream* os) { + if (p == NULL) { + *os << "NULL"; + } else { + // T is a function type, so '*os << p' doesn't do what we want + // (it just prints p as bool). We want to print p as a const + // void*. + *os << reinterpret_cast<const void*>(p); } } // Used to print a non-container, non-pointer value when the user // doesn't define PrintTo() for it. template <typename T> -void DefaultPrintTo(IsNotContainer /* dummy */, - false_type /* is not a pointer */, +void DefaultPrintTo(WrapPrinterType<kPrintOther> /* dummy */, const T& value, ::std::ostream* os) { ::testing_internal::DefaultPrintNonContainerTo(value, os); } @@ -452,11 +491,8 @@ void DefaultPrintTo(IsNotContainer /* dummy */, // wants). template <typename T> void PrintTo(const T& value, ::std::ostream* os) { - // DefaultPrintTo() is overloaded. The type of its first two - // arguments determine which version will be picked. If T is an - // STL-style container, the version for container will be called; if - // T is a pointer, the pointer version will be called; otherwise the - // generic version will be called. + // DefaultPrintTo() is overloaded. The type of its first argument + // determines which version will be picked. // // Note that we check for container types here, prior to we check // for protocol message types in our operator<<. The rationale is: @@ -468,13 +504,27 @@ void PrintTo(const T& value, ::std::ostream* os) { // elements; therefore we check for container types here to ensure // that our format is used. // - // The second argument of DefaultPrintTo() is needed to bypass a bug - // in Symbian's C++ compiler that prevents it from picking the right - // overload between: - // - // PrintTo(const T& x, ...); - // PrintTo(T* x, ...); - DefaultPrintTo(IsContainerTest<T>(0), is_pointer<T>(), value, os); + // Note that MSVC and clang-cl do allow an implicit conversion from + // pointer-to-function to pointer-to-object, but clang-cl warns on it. + // So don't use ImplicitlyConvertible if it can be helped since it will + // cause this warning, and use a separate overload of DefaultPrintTo for + // function pointers so that the `*os << p` in the object pointer overload + // doesn't cause that warning either. + DefaultPrintTo( + WrapPrinterType < + (sizeof(IsContainerTest<T>(0)) == sizeof(IsContainer)) && + !IsRecursiveContainer<T>::value + ? kPrintContainer + : !is_pointer<T>::value + ? kPrintOther +#if GTEST_LANG_CXX11 + : std::is_function<typename std::remove_pointer<T>::type>::value +#else + : !internal::ImplicitlyConvertible<T, const void*>::value +#endif + ? kPrintFunctionPointer + : kPrintPointer > (), + value, os); } // The following list of PrintTo() overloads tells @@ -581,6 +631,17 @@ inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { } #endif // GTEST_HAS_STD_WSTRING +#if GTEST_HAS_ABSL +// Overload for absl::string_view. +inline void PrintTo(absl::string_view sp, ::std::ostream* os) { + PrintTo(::std::string(sp), os); +} +#endif // GTEST_HAS_ABSL + +#if GTEST_LANG_CXX11 +inline void PrintTo(std::nullptr_t, ::std::ostream* os) { *os << "(nullptr)"; } +#endif // GTEST_LANG_CXX11 + #if GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_ // Helper function for printing a tuple. T must be instantiated with // a tuple type. @@ -710,6 +771,48 @@ class UniversalPrinter { GTEST_DISABLE_MSC_WARNINGS_POP_() }; +#if GTEST_HAS_ABSL + +// Printer for absl::optional + +template <typename T> +class UniversalPrinter<::absl::optional<T>> { + public: + static void Print(const ::absl::optional<T>& value, ::std::ostream* os) { + *os << '('; + if (!value) { + *os << "nullopt"; + } else { + UniversalPrint(*value, os); + } + *os << ')'; + } +}; + +// Printer for absl::variant + +template <typename... T> +class UniversalPrinter<::absl::variant<T...>> { + public: + static void Print(const ::absl::variant<T...>& value, ::std::ostream* os) { + *os << '('; + absl::visit(Visitor{os}, value); + *os << ')'; + } + + private: + struct Visitor { + template <typename U> + void operator()(const U& u) const { + *os << "'" << GetTypeName<U>() << "' with value "; + UniversalPrint(u, os); + } + ::std::ostream* os; + }; +}; + +#endif // GTEST_HAS_ABSL + // UniversalPrintArray(begin, len, os) prints an array of 'len' // elements, starting at address 'begin'. template <typename T> @@ -723,7 +826,7 @@ void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { // If the array has more than kThreshold elements, we'll have to // omit some details by printing only the first and the last // kChunkSize elements. - // TODO(wan@google.com): let the user control the threshold using a flag. + // FIXME: let the user control the threshold using a flag. if (len <= kThreshold) { PrintRawArrayTo(begin, len, os); } else { @@ -805,7 +908,7 @@ class UniversalTersePrinter<const char*> { if (str == NULL) { *os << "NULL"; } else { - UniversalPrint(string(str), os); + UniversalPrint(std::string(str), os); } } }; @@ -856,7 +959,7 @@ void UniversalPrint(const T& value, ::std::ostream* os) { UniversalPrinter<T1>::Print(value, os); } -typedef ::std::vector<string> Strings; +typedef ::std::vector< ::std::string> Strings; // TuplePolicy<TupleT> must provide: // - tuple_size @@ -875,12 +978,13 @@ struct TuplePolicy { static const size_t tuple_size = ::std::tr1::tuple_size<Tuple>::value; template <size_t I> - struct tuple_element : ::std::tr1::tuple_element<I, Tuple> {}; + struct tuple_element : ::std::tr1::tuple_element<static_cast<int>(I), Tuple> { + }; template <size_t I> - static typename AddReference< - const typename ::std::tr1::tuple_element<I, Tuple>::type>::type get( - const Tuple& tuple) { + static typename AddReference<const typename ::std::tr1::tuple_element< + static_cast<int>(I), Tuple>::type>::type + get(const Tuple& tuple) { return ::std::tr1::get<I>(tuple); } }; @@ -976,6 +1080,16 @@ Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { } // namespace internal +#if GTEST_HAS_ABSL +namespace internal2 { +template <typename T> +void TypeWithoutFormatter<T, kConvertibleToStringView>::PrintValue( + const T& value, ::std::ostream* os) { + internal::PrintTo(absl::string_view(value), os); +} +} // namespace internal2 +#endif + template <typename T> ::std::string PrintToString(const T& value) { ::std::stringstream ss; diff --git a/test/googletest/include/gtest/gtest-spi.h b/test/googletest/include/gtest/gtest-spi.h index f63fa9a1..1e898393 100644 --- a/test/googletest/include/gtest/gtest-spi.h +++ b/test/googletest/include/gtest/gtest-spi.h @@ -26,17 +26,21 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) + // // Utilities for testing Google Test itself and code that uses Google Test // (e.g. frameworks built on top of Google Test). +// GOOGLETEST_CM0004 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_ #define GTEST_INCLUDE_GTEST_GTEST_SPI_H_ #include "gtest/gtest.h" +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + namespace testing { // This helper class can be used to mock out Google Test failure reporting @@ -97,13 +101,12 @@ class GTEST_API_ SingleFailureChecker { public: // The constructor remembers the arguments. SingleFailureChecker(const TestPartResultArray* results, - TestPartResult::Type type, - const string& substr); + TestPartResult::Type type, const std::string& substr); ~SingleFailureChecker(); private: const TestPartResultArray* const results_; const TestPartResult::Type type_; - const string substr_; + const std::string substr_; GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker); }; @@ -112,6 +115,8 @@ class GTEST_API_ SingleFailureChecker { } // namespace testing +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + // A set of macros for testing Google Test assertions or code that's expected // to generate Google Test fatal failures. It verifies that the given // statement will cause exactly one fatal Google Test failure with 'substr' diff --git a/test/googletest/include/gtest/gtest-test-part.h b/test/googletest/include/gtest/gtest-test-part.h index 77eb8448..1c7b89e0 100644 --- a/test/googletest/include/gtest/gtest-test-part.h +++ b/test/googletest/include/gtest/gtest-test-part.h @@ -27,8 +27,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Author: mheule@google.com (Markus Heule) -// +// GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ #define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ @@ -38,6 +37,9 @@ #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-string.h" +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + namespace testing { // A copyable object representing the result of a test part (i.e. an @@ -143,7 +145,7 @@ class GTEST_API_ TestPartResultArray { }; // This interface knows how to report a test part result. -class TestPartResultReporterInterface { +class GTEST_API_ TestPartResultReporterInterface { public: virtual ~TestPartResultReporterInterface() {} @@ -176,4 +178,6 @@ class GTEST_API_ HasNewFatalFailureHelper } // namespace testing +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + #endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ diff --git a/test/googletest/include/gtest/gtest-typed-test.h b/test/googletest/include/gtest/gtest-typed-test.h index 5f69d567..74bce46b 100644 --- a/test/googletest/include/gtest/gtest-typed-test.h +++ b/test/googletest/include/gtest/gtest-typed-test.h @@ -26,8 +26,9 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) + + +// GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ @@ -82,6 +83,24 @@ TYPED_TEST(FooTest, DoesBlah) { TYPED_TEST(FooTest, HasPropertyA) { ... } +// TYPED_TEST_CASE takes an optional third argument which allows to specify a +// class that generates custom test name suffixes based on the type. This should +// be a class which has a static template function GetName(int index) returning +// a string for each type. The provided integer index equals the index of the +// type in the provided type list. In many cases the index can be ignored. +// +// For example: +// class MyTypeNames { +// public: +// template <typename T> +// static std::string GetName(int) { +// if (std::is_same<T, char>()) return "char"; +// if (std::is_same<T, int>()) return "int"; +// if (std::is_same<T, unsigned int>()) return "unsignedInt"; +// } +// }; +// TYPED_TEST_CASE(FooTest, MyTypes, MyTypeNames); + #endif // 0 // Type-parameterized tests are abstract test patterns parameterized @@ -143,6 +162,11 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); // If the type list contains only one type, you can write that type // directly without Types<...>: // INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int); +// +// Similar to the optional argument of TYPED_TEST_CASE above, +// INSTANTIATE_TEST_CASE_P takes an optional fourth argument which allows to +// generate custom names. +// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes, MyTypeNames); #endif // 0 @@ -159,32 +183,46 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); // given test case. # define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_ +// Expands to the name of the typedef for the NameGenerator, responsible for +// creating the suffixes of the name. +#define GTEST_NAME_GENERATOR_(TestCaseName) \ + gtest_type_params_##TestCaseName##_NameGenerator + // The 'Types' template argument below must have spaces around it // since some compilers may choke on '>>' when passing a template // instance (e.g. Types<int>) -# define TYPED_TEST_CASE(CaseName, Types) \ - typedef ::testing::internal::TypeList< Types >::type \ - GTEST_TYPE_PARAMS_(CaseName) - -# define TYPED_TEST(CaseName, TestName) \ - template <typename gtest_TypeParam_> \ - class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ - : public CaseName<gtest_TypeParam_> { \ - private: \ - typedef CaseName<gtest_TypeParam_> TestFixture; \ - typedef gtest_TypeParam_ TypeParam; \ - virtual void TestBody(); \ - }; \ - bool gtest_##CaseName##_##TestName##_registered_ GTEST_ATTRIBUTE_UNUSED_ = \ - ::testing::internal::TypeParameterizedTest< \ - CaseName, \ - ::testing::internal::TemplateSel< \ - GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \ - GTEST_TYPE_PARAMS_(CaseName)>::Register(\ - "", ::testing::internal::CodeLocation(__FILE__, __LINE__), \ - #CaseName, #TestName, 0); \ - template <typename gtest_TypeParam_> \ - void GTEST_TEST_CLASS_NAME_(CaseName, TestName)<gtest_TypeParam_>::TestBody() +# define TYPED_TEST_CASE(CaseName, Types, ...) \ + typedef ::testing::internal::TypeList< Types >::type GTEST_TYPE_PARAMS_( \ + CaseName); \ + typedef ::testing::internal::NameGeneratorSelector<__VA_ARGS__>::type \ + GTEST_NAME_GENERATOR_(CaseName) + +# define TYPED_TEST(CaseName, TestName) \ + template <typename gtest_TypeParam_> \ + class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ + : public CaseName<gtest_TypeParam_> { \ + private: \ + typedef CaseName<gtest_TypeParam_> TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + virtual void TestBody(); \ + }; \ + static bool gtest_##CaseName##_##TestName##_registered_ \ + GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::internal::TypeParameterizedTest< \ + CaseName, \ + ::testing::internal::TemplateSel<GTEST_TEST_CLASS_NAME_(CaseName, \ + TestName)>, \ + GTEST_TYPE_PARAMS_( \ + CaseName)>::Register("", \ + ::testing::internal::CodeLocation( \ + __FILE__, __LINE__), \ + #CaseName, #TestName, 0, \ + ::testing::internal::GenerateNames< \ + GTEST_NAME_GENERATOR_(CaseName), \ + GTEST_TYPE_PARAMS_(CaseName)>()); \ + template <typename gtest_TypeParam_> \ + void GTEST_TEST_CLASS_NAME_(CaseName, \ + TestName)<gtest_TypeParam_>::TestBody() #endif // GTEST_HAS_TYPED_TEST @@ -241,22 +279,27 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); namespace GTEST_CASE_NAMESPACE_(CaseName) { \ typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \ } \ - static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \ - GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\ - __FILE__, __LINE__, #__VA_ARGS__) + static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) \ + GTEST_ATTRIBUTE_UNUSED_ = \ + GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames( \ + __FILE__, __LINE__, #__VA_ARGS__) // The 'Types' template argument below must have spaces around it // since some compilers may choke on '>>' when passing a template // instance (e.g. Types<int>) -# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \ - bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \ - ::testing::internal::TypeParameterizedTestCase<CaseName, \ - GTEST_CASE_NAMESPACE_(CaseName)::gtest_AllTests_, \ - ::testing::internal::TypeList< Types >::type>::Register(\ - #Prefix, \ - ::testing::internal::CodeLocation(__FILE__, __LINE__), \ - >EST_TYPED_TEST_CASE_P_STATE_(CaseName), \ - #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName)) +# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types, ...) \ + static bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::internal::TypeParameterizedTestCase< \ + CaseName, GTEST_CASE_NAMESPACE_(CaseName)::gtest_AllTests_, \ + ::testing::internal::TypeList< Types >::type>:: \ + Register(#Prefix, \ + ::testing::internal::CodeLocation(__FILE__, __LINE__), \ + >EST_TYPED_TEST_CASE_P_STATE_(CaseName), #CaseName, \ + GTEST_REGISTERED_TEST_NAMES_(CaseName), \ + ::testing::internal::GenerateNames< \ + ::testing::internal::NameGeneratorSelector< \ + __VA_ARGS__>::type, \ + ::testing::internal::TypeList< Types >::type>()) #endif // GTEST_HAS_TYPED_TEST_P diff --git a/test/googletest/include/gtest/gtest.h b/test/googletest/include/gtest/gtest.h index f846c5bd..5df4b0a3 100644 --- a/test/googletest/include/gtest/gtest.h +++ b/test/googletest/include/gtest/gtest.h @@ -26,10 +26,9 @@ // 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. + // -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file defines the public API for Google Test. It should be // included by any test program that uses Google Test. @@ -48,6 +47,8 @@ // registration from Barthelemy Dagenais' (barthelemy@prologique.com) // easyUnit framework. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_GTEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_H_ @@ -65,6 +66,9 @@ #include "gtest/gtest-test-part.h" #include "gtest/gtest-typed-test.h" +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + // Depending on the platform, different string classes are available. // On Linux, in addition to ::std::string, Google also makes use of // class ::string, which has the same interface as ::std::string, but @@ -82,6 +86,15 @@ namespace testing { +// Silence C4100 (unreferenced formal parameter) and 4805 +// unsafe mix of type 'const int' and type 'const bool' +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4805) +# pragma warning(disable:4100) +#endif + + // Declares the flags. // This flag temporary enables the disabled tests. @@ -103,6 +116,10 @@ GTEST_DECLARE_string_(color); // the tests to run. If the filter is not given all tests are executed. GTEST_DECLARE_string_(filter); +// This flag controls whether Google Test installs a signal handler that dumps +// debugging information when fatal signals are raised. +GTEST_DECLARE_bool_(install_failure_signal_handler); + // This flag causes the Google Test to list tests. None of the tests listed // are actually run if the flag is provided. GTEST_DECLARE_bool_(list_tests); @@ -115,6 +132,9 @@ GTEST_DECLARE_string_(output); // test. GTEST_DECLARE_bool_(print_time); +// This flags control whether Google Test prints UTF8 characters as text. +GTEST_DECLARE_bool_(print_utf8); + // This flag specifies the random number seed. GTEST_DECLARE_int32_(random_seed); @@ -135,7 +155,7 @@ GTEST_DECLARE_int32_(stack_trace_depth); // When this flag is specified, a failed assertion will throw an // exception if exceptions are enabled, or exit the program with a -// non-zero code otherwise. +// non-zero code otherwise. For use with an external test framework. GTEST_DECLARE_bool_(throw_on_failure); // When this flag is set with a "host:port" string, on supported @@ -143,6 +163,10 @@ GTEST_DECLARE_bool_(throw_on_failure); // the specified host machine. GTEST_DECLARE_string_(stream_result_to); +#if GTEST_USE_OWN_FLAGFILE_FLAG_ +GTEST_DECLARE_string_(flagfile); +#endif // GTEST_USE_OWN_FLAGFILE_FLAG_ + // The upper limit for valid stack trace depths. const int kMaxStackTraceDepth = 100; @@ -160,6 +184,7 @@ class TestEventListenersAccessor; class TestEventRepeater; class UnitTestRecordPropertyTestHelper; class WindowsDeathTest; +class FuchsiaDeathTest; class UnitTestImpl* GetUnitTestImpl(); void ReportFailureInUnknownLocation(TestPartResult::Type result_type, const std::string& message); @@ -259,7 +284,9 @@ class GTEST_API_ AssertionResult { // Used in EXPECT_TRUE/FALSE(assertion_result). AssertionResult(const AssertionResult& other); +#if defined(_MSC_VER) && _MSC_VER < 1910 GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 /* forcing value to bool */) +#endif // Used in the EXPECT_TRUE/FALSE(bool_expression). // @@ -276,7 +303,9 @@ class GTEST_API_ AssertionResult { /*enabler*/ = NULL) : success_(success) {} +#if defined(_MSC_VER) && _MSC_VER < 1910 GTEST_DISABLE_MSC_WARNINGS_POP_() +#endif // Assignment operator. AssertionResult& operator=(AssertionResult other) { @@ -297,7 +326,7 @@ class GTEST_API_ AssertionResult { const char* message() const { return message_.get() != NULL ? message_->c_str() : ""; } - // TODO(vladl@google.com): Remove this after making sure no clients use it. + // FIXME: Remove this after making sure no clients use it. // Deprecated; please use message() instead. const char* failure_message() const { return message(); } @@ -345,6 +374,15 @@ GTEST_API_ AssertionResult AssertionFailure(); // Deprecated; use AssertionFailure() << msg. GTEST_API_ AssertionResult AssertionFailure(const Message& msg); +} // namespace testing + +// Includes the auto-generated header that implements a family of generic +// predicate assertion macros. This include comes late because it relies on +// APIs declared above. +#include "gtest/gtest_pred_impl.h" + +namespace testing { + // The abstract class that all tests inherit from. // // In Google Test, a unit test program contains one or many TestCases, and @@ -355,7 +393,7 @@ GTEST_API_ AssertionResult AssertionFailure(const Message& msg); // this for you. // // The only time you derive from Test is when defining a test fixture -// to be used a TEST_F. For example: +// to be used in a TEST_F. For example: // // class FooTest : public testing::Test { // protected: @@ -550,9 +588,8 @@ class GTEST_API_ TestResult { // Returns the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } - // Returns the i-th test part result among all the results. i can range - // from 0 to test_property_count() - 1. If i is not in that range, aborts - // the program. + // Returns the i-th test part result among all the results. i can range from 0 + // to total_part_count() - 1. If i is not in that range, aborts the program. const TestPartResult& GetTestPartResult(int i) const; // Returns the i-th test property. i can range from 0 to @@ -569,6 +606,7 @@ class GTEST_API_ TestResult { friend class internal::TestResultAccessor; friend class internal::UnitTestImpl; friend class internal::WindowsDeathTest; + friend class internal::FuchsiaDeathTest; // Gets the vector of TestPartResults. const std::vector<TestPartResult>& test_part_results() const { @@ -594,7 +632,7 @@ class GTEST_API_ TestResult { // Adds a failure if the key is a reserved attribute of Google Test // testcase tags. Returns true if the property is valid. - // TODO(russr): Validate attribute names are legal and human readable. + // FIXME: Validate attribute names are legal and human readable. static bool ValidateTestProperty(const std::string& xml_element, const TestProperty& test_property); @@ -675,6 +713,9 @@ class GTEST_API_ TestInfo { // Returns the line where this test is defined. int line() const { return location_.line; } + // Return true if this test should not be run because it's in another shard. + bool is_in_another_shard() const { return is_in_another_shard_; } + // Returns true if this test should run, that is if the test is not // disabled (or it is disabled but the also_run_disabled_tests flag has // been specified) and its full name matches the user-specified filter. @@ -695,10 +736,9 @@ class GTEST_API_ TestInfo { // Returns true iff this test will appear in the XML report. bool is_reportable() const { - // For now, the XML report includes all tests matching the filter. - // In the future, we may trim tests that are excluded because of - // sharding. - return matches_filter_; + // The XML report includes tests matching the filter, excluding those + // run in other shards. + return matches_filter_ && !is_in_another_shard_; } // Returns the result of the test. @@ -762,6 +802,7 @@ class GTEST_API_ TestInfo { bool is_disabled_; // True iff this test is disabled bool matches_filter_; // True if this test matches the // user-specified filter. + bool is_in_another_shard_; // Will be run in another shard. internal::TestFactoryBase* const factory_; // The factory that creates // the test object @@ -986,6 +1027,18 @@ class Environment { virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } }; +#if GTEST_HAS_EXCEPTIONS + +// Exception which can be thrown from TestEventListener::OnTestPartResult. +class GTEST_API_ AssertionException + : public internal::GoogleTestFailureException { + public: + explicit AssertionException(const TestPartResult& result) + : GoogleTestFailureException(result) {} +}; + +#endif // GTEST_HAS_EXCEPTIONS + // The interface for tracing execution of tests. The methods are organized in // the order the corresponding events are fired. class TestEventListener { @@ -1014,6 +1067,8 @@ class TestEventListener { virtual void OnTestStart(const TestInfo& test_info) = 0; // Fired after a failed assertion or a SUCCEED() invocation. + // If you want to throw an exception from this function to skip to the next + // TEST, it must be AssertionException defined above, or inherited from it. virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0; // Fired after the test ends. @@ -1180,14 +1235,12 @@ class GTEST_API_ UnitTest { // Returns the random seed used at the start of the current test run. int random_seed() const; -#if GTEST_HAS_PARAM_TEST // Returns the ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. internal::ParameterizedTestCaseRegistry& parameterized_test_registry() GTEST_LOCK_EXCLUDED_(mutex_); -#endif // GTEST_HAS_PARAM_TEST // Gets the number of successful test cases. int successful_test_case_count() const; @@ -1287,11 +1340,11 @@ class GTEST_API_ UnitTest { internal::UnitTestImpl* impl() { return impl_; } const internal::UnitTestImpl* impl() const { return impl_; } - // These classes and funcions are friends as they need to access private + // These classes and functions are friends as they need to access private // members of UnitTest. + friend class ScopedTrace; friend class Test; friend class internal::AssertHelper; - friend class internal::ScopedTrace; friend class internal::StreamingListenerTest; friend class internal::UnitTestRecordPropertyTestHelper; friend Environment* AddGlobalTestEnvironment(Environment* env); @@ -1388,11 +1441,9 @@ AssertionResult CmpHelperEQ(const char* lhs_expression, const char* rhs_expression, const T1& lhs, const T2& rhs) { -GTEST_DISABLE_MSC_WARNINGS_PUSH_(4389 /* signed/unsigned mismatch */) if (lhs == rhs) { return AssertionSuccess(); } -GTEST_DISABLE_MSC_WARNINGS_POP_() return CmpHelperEQFailure(lhs_expression, rhs_expression, lhs, rhs); } @@ -1706,7 +1757,6 @@ class GTEST_API_ AssertHelper { } // namespace internal -#if GTEST_HAS_PARAM_TEST // The pure interface class that all value-parameterized tests inherit from. // A value-parameterized class must inherit from both ::testing::Test and // ::testing::WithParamInterface. In most cases that just means inheriting @@ -1783,8 +1833,6 @@ template <typename T> class TestWithParam : public Test, public WithParamInterface<T> { }; -#endif // GTEST_HAS_PARAM_TEST - // Macros for indicating success/failure in test code. // ADD_FAILURE unconditionally adds a failure to the current test. @@ -1857,22 +1905,18 @@ class TestWithParam : public Test, public WithParamInterface<T> { // AssertionResult. For more information on how to use AssertionResult with // these macros see comments on that class. #define EXPECT_TRUE(condition) \ - GTEST_TEST_BOOLEAN_((condition), #condition, false, true, \ + GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ GTEST_NONFATAL_FAILURE_) #define EXPECT_FALSE(condition) \ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ GTEST_NONFATAL_FAILURE_) #define ASSERT_TRUE(condition) \ - GTEST_TEST_BOOLEAN_((condition), #condition, false, true, \ + GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ GTEST_FATAL_FAILURE_) #define ASSERT_FALSE(condition) \ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ GTEST_FATAL_FAILURE_) -// Includes the auto-generated header that implements a family of -// generic predicate assertion macros. -#include "gtest/gtest_pred_impl.h" - // Macros for testing equalities and inequalities. // // * {ASSERT|EXPECT}_EQ(v1, v2): Tests that v1 == v2 @@ -1914,8 +1958,8 @@ class TestWithParam : public Test, public WithParamInterface<T> { // // Examples: // -// EXPECT_NE(5, Foo()); -// EXPECT_EQ(NULL, a_pointer); +// EXPECT_NE(Foo(), 5); +// EXPECT_EQ(a_pointer, NULL); // ASSERT_LT(i, array_size); // ASSERT_GT(records.size(), 0) << "There is no record left."; @@ -2101,6 +2145,57 @@ GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, #define EXPECT_NO_FATAL_FAILURE(statement) \ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_) +// Causes a trace (including the given source file path and line number, +// and the given message) to be included in every test failure message generated +// by code in the scope of the lifetime of an instance of this class. The effect +// is undone with the destruction of the instance. +// +// The message argument can be anything streamable to std::ostream. +// +// Example: +// testing::ScopedTrace trace("file.cc", 123, "message"); +// +class GTEST_API_ ScopedTrace { + public: + // The c'tor pushes the given source file location and message onto + // a trace stack maintained by Google Test. + + // Template version. Uses Message() to convert the values into strings. + // Slow, but flexible. + template <typename T> + ScopedTrace(const char* file, int line, const T& message) { + PushTrace(file, line, (Message() << message).GetString()); + } + + // Optimize for some known types. + ScopedTrace(const char* file, int line, const char* message) { + PushTrace(file, line, message ? message : "(null)"); + } + +#if GTEST_HAS_GLOBAL_STRING + ScopedTrace(const char* file, int line, const ::string& message) { + PushTrace(file, line, message); + } +#endif + + ScopedTrace(const char* file, int line, const std::string& message) { + PushTrace(file, line, message); + } + + // The d'tor pops the info pushed by the c'tor. + // + // Note that the d'tor is not virtual in order to be efficient. + // Don't inherit from ScopedTrace! + ~ScopedTrace(); + + private: + void PushTrace(const char* file, int line, std::string message); + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); +} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its + // c'tor and d'tor. Therefore it doesn't + // need to be used otherwise. + // Causes a trace (including the source file path, the current line // number, and the given message) to be included in every test failure // message generated by code in the current scope. The effect is @@ -2112,9 +2207,14 @@ GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, // of the dummy variable name, thus allowing multiple SCOPED_TRACE()s // to appear in the same block - as long as they are on different // lines. +// +// Assuming that each thread maintains its own stack of traces. +// Therefore, a SCOPED_TRACE() would (correctly) only affect the +// assertions in its own thread. #define SCOPED_TRACE(message) \ - ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ - __FILE__, __LINE__, ::testing::Message() << (message)) + ::testing::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ + __FILE__, __LINE__, (message)) + // Compile-time assertion for type equality. // StaticAssertTypeEq<type1, type2>() compiles iff type1 and type2 are @@ -2194,7 +2294,7 @@ bool StaticAssertTypeEq() { // name of the test within the test case. // // A test fixture class must be declared earlier. The user should put -// his test code between braces after using this macro. Example: +// the test code between braces after using this macro. Example: // // class FooTest : public testing::Test { // protected: @@ -2209,14 +2309,22 @@ bool StaticAssertTypeEq() { // } // // TEST_F(FooTest, ReturnsElementCountCorrectly) { -// EXPECT_EQ(0, a_.size()); -// EXPECT_EQ(1, b_.size()); +// EXPECT_EQ(a_.size(), 0); +// EXPECT_EQ(b_.size(), 1); // } #define TEST_F(test_fixture, test_name)\ GTEST_TEST_(test_fixture, test_name, test_fixture, \ ::testing::internal::GetTypeId<test_fixture>()) +// Returns a path to temporary directory. +// Tries to determine an appropriate directory for the platform. +GTEST_API_ std::string TempDir(); + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + } // namespace testing // Use this function in main() to run all tests. It returns 0 if all @@ -2233,4 +2341,6 @@ inline int RUN_ALL_TESTS() { return ::testing::UnitTest::GetInstance()->Run(); } +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + #endif // GTEST_INCLUDE_GTEST_GTEST_H_ diff --git a/test/googletest/include/gtest/gtest_pred_impl.h b/test/googletest/include/gtest/gtest_pred_impl.h index 30ae712f..0c1105cb 100644 --- a/test/googletest/include/gtest/gtest_pred_impl.h +++ b/test/googletest/include/gtest/gtest_pred_impl.h @@ -27,18 +27,19 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// This file is AUTOMATICALLY GENERATED on 10/31/2011 by command +// This file is AUTOMATICALLY GENERATED on 01/02/2018 by command // 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! // // Implements a family of generic predicate assertion macros. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ #define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ -// Makes sure this header is not included before gtest.h. -#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ -# error Do not include gtest_pred_impl.h directly. Include gtest.h instead. -#endif // GTEST_INCLUDE_GTEST_GTEST_H_ +#include "gtest/gtest.h" + +namespace testing { // This header implements a family of generic predicate assertion // macros: @@ -66,8 +67,6 @@ // We also define the EXPECT_* variations. // // For now we only support predicates whose arity is at most 5. -// Please email googletestframework@googlegroups.com if you need -// support for higher arities. // GTEST_ASSERT_ is the basic statement to which all of the assertions // in this file reduce. Don't use this in your code. @@ -355,4 +354,6 @@ AssertionResult AssertPred5Helper(const char* pred_text, +} // namespace testing + #endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ diff --git a/test/googletest/include/gtest/gtest_prod.h b/test/googletest/include/gtest/gtest_prod.h index da80ddc6..e651671e 100644 --- a/test/googletest/include/gtest/gtest_prod.h +++ b/test/googletest/include/gtest/gtest_prod.h @@ -26,10 +26,10 @@ // 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. + // -// Author: wan@google.com (Zhanyong Wan) -// -// Google C++ Testing Framework definitions useful in production code. +// Google C++ Testing and Mocking Framework definitions useful in production code. +// GOOGLETEST_CM0003 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_ #define GTEST_INCLUDE_GTEST_GTEST_PROD_H_ @@ -40,17 +40,20 @@ // // class MyClass { // private: -// void MyMethod(); -// FRIEND_TEST(MyClassTest, MyMethod); +// void PrivateMethod(); +// FRIEND_TEST(MyClassTest, PrivateMethodWorks); // }; // // class MyClassTest : public testing::Test { // // ... // }; // -// TEST_F(MyClassTest, MyMethod) { -// // Can call MyClass::MyMethod() here. +// TEST_F(MyClassTest, PrivateMethodWorks) { +// // Can call MyClass::PrivateMethod() here. // } +// +// Note: The test class must be in the same namespace as the class being tested. +// For example, putting MyClassTest in an anonymous namespace will not work. #define FRIEND_TEST(test_case_name, test_name)\ friend class test_case_name##_##test_name##_Test diff --git a/test/googletest/include/gtest/internal/gtest-death-test-internal.h b/test/googletest/include/gtest/internal/gtest-death-test-internal.h index 2b3a78f5..0a9b42c8 100644 --- a/test/googletest/include/gtest/internal/gtest-death-test-internal.h +++ b/test/googletest/include/gtest/internal/gtest-death-test-internal.h @@ -27,12 +27,11 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file defines internal utilities needed for implementing // death tests. They are subject to change without notice. +// GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ @@ -53,6 +52,9 @@ const char kInternalRunDeathTestFlag[] = "internal_run_death_test"; #if GTEST_HAS_DEATH_TEST +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + // DeathTest is a class that hides much of the complexity of the // GTEST_DEATH_TEST_ macro. It is abstract; its static Create method // returns a concrete class that depends on the prevailing death test @@ -136,6 +138,8 @@ class GTEST_API_ DeathTest { GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest); }; +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + // Factory interface for death tests. May be mocked out for testing. class DeathTestFactory { public: @@ -218,14 +222,18 @@ GTEST_API_ bool ExitedUnsuccessfully(int exit_status); // can be streamed. // This macro is for implementing ASSERT/EXPECT_DEBUG_DEATH when compiled in -// NDEBUG mode. In this case we need the statements to be executed, the regex is -// ignored, and the macro must accept a streamed message even though the message -// is never printed. -# define GTEST_EXECUTE_STATEMENT_(statement, regex) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - } else \ +// NDEBUG mode. In this case we need the statements to be executed and the macro +// must accept a streamed message even though the message is never printed. +// The regex object is not evaluated, but it is used to prevent "unused" +// warnings and to avoid an expression that doesn't compile in debug mode. +#define GTEST_EXECUTE_STATEMENT_(statement, regex) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } else if (!::testing::internal::AlwaysTrue()) { \ + const ::testing::internal::RE& gtest_regex = (regex); \ + static_cast<void>(gtest_regex); \ + } else \ ::testing::Message() // A class representing the parsed contents of the @@ -264,53 +272,6 @@ class InternalRunDeathTestFlag { // the flag is specified; otherwise returns NULL. InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag(); -#else // GTEST_HAS_DEATH_TEST - -// This macro is used for implementing macros such as -// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where -// death tests are not supported. Those macros must compile on such systems -// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on -// systems that support death tests. This allows one to write such a macro -// on a system that does not support death tests and be sure that it will -// compile on a death-test supporting system. -// -// Parameters: -// statement - A statement that a macro such as EXPECT_DEATH would test -// for program termination. This macro has to make sure this -// statement is compiled but not executed, to ensure that -// EXPECT_DEATH_IF_SUPPORTED compiles with a certain -// parameter iff EXPECT_DEATH compiles with it. -// regex - A regex that a macro such as EXPECT_DEATH would use to test -// the output of statement. This parameter has to be -// compiled but not evaluated by this macro, to ensure that -// this macro only accepts expressions that a macro such as -// EXPECT_DEATH would accept. -// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED -// and a return statement for ASSERT_DEATH_IF_SUPPORTED. -// This ensures that ASSERT_DEATH_IF_SUPPORTED will not -// compile inside functions where ASSERT_DEATH doesn't -// compile. -// -// The branch that has an always false condition is used to ensure that -// statement and regex are compiled (and thus syntactically correct) but -// never executed. The unreachable code macro protects the terminator -// statement from generating an 'unreachable code' warning in case -// statement unconditionally returns or throws. The Message constructor at -// the end allows the syntax of streaming additional messages into the -// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH. -# define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - GTEST_LOG_(WARNING) \ - << "Death tests are not supported on this platform.\n" \ - << "Statement '" #statement "' cannot be verified."; \ - } else if (::testing::internal::AlwaysFalse()) { \ - ::testing::internal::RE::PartialMatch(".*", (regex)); \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - terminator; \ - } else \ - ::testing::Message() - #endif // GTEST_HAS_DEATH_TEST } // namespace internal diff --git a/test/googletest/include/gtest/internal/gtest-filepath.h b/test/googletest/include/gtest/internal/gtest-filepath.h index 7a13b4b0..ae38d95b 100644 --- a/test/googletest/include/gtest/internal/gtest-filepath.h +++ b/test/googletest/include/gtest/internal/gtest-filepath.h @@ -27,21 +27,24 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Author: keith.ray@gmail.com (Keith Ray) -// // Google Test filepath utilities // // This header file declares classes and functions used internally by // Google Test. They are subject to change without notice. // -// This file is #included in <gtest/internal/gtest-internal.h>. +// This file is #included in gtest/internal/gtest-internal.h. // Do not include this header file separately! +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ #include "gtest/internal/gtest-string.h" +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + namespace testing { namespace internal { @@ -203,4 +206,6 @@ class GTEST_API_ FilePath { } // namespace internal } // namespace testing +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ diff --git a/test/googletest/include/gtest/internal/gtest-internal.h b/test/googletest/include/gtest/internal/gtest-internal.h index ebd1cf61..b762f61f 100644 --- a/test/googletest/include/gtest/internal/gtest-internal.h +++ b/test/googletest/include/gtest/internal/gtest-internal.h @@ -27,13 +27,13 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file declares functions and macros used internally by // Google Test. They are subject to change without notice. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ @@ -61,8 +61,8 @@ #include <vector> #include "gtest/gtest-message.h" -#include "gtest/internal/gtest-string.h" #include "gtest/internal/gtest-filepath.h" +#include "gtest/internal/gtest-string.h" #include "gtest/internal/gtest-type-util.h" // Due to C++ preprocessor weirdness, we need double indirection to @@ -76,6 +76,9 @@ #define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar) #define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar +// Stringifies its argument. +#define GTEST_STRINGIFY_(name) #name + class ProtocolMessage; namespace proto2 { class Message; } @@ -96,7 +99,6 @@ template <typename T> namespace internal { struct TraceInfo; // Information about a trace point. -class ScopedTrace; // Implements scoped trace. class TestInfoImpl; // Opaque implementation of TestInfo class UnitTestImpl; // Opaque implementation of UnitTest @@ -139,6 +141,9 @@ GTEST_API_ std::string AppendUserMessage( #if GTEST_HAS_EXCEPTIONS +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4275 \ +/* an exported class was derived from a class that was not exported */) + // This exception is thrown by (and only by) a failed Google Test // assertion when GTEST_FLAG(throw_on_failure) is true (if exceptions // are enabled). We derive it from std::runtime_error, which is for @@ -150,32 +155,15 @@ class GTEST_API_ GoogleTestFailureException : public ::std::runtime_error { explicit GoogleTestFailureException(const TestPartResult& failure); }; -#endif // GTEST_HAS_EXCEPTIONS +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4275 -// A helper class for creating scoped traces in user programs. -class GTEST_API_ ScopedTrace { - public: - // The c'tor pushes the given source file location and message onto - // a trace stack maintained by Google Test. - ScopedTrace(const char* file, int line, const Message& message); - - // The d'tor pops the info pushed by the c'tor. - // - // Note that the d'tor is not virtual in order to be efficient. - // Don't inherit from ScopedTrace! - ~ScopedTrace(); - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); -} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its - // c'tor and d'tor. Therefore it doesn't - // need to be used otherwise. +#endif // GTEST_HAS_EXCEPTIONS namespace edit_distance { // Returns the optimal edits to go from 'left' to 'right'. // All edits cost the same, with replace having lower priority than // add/remove. -// Simple implementation of the Wagner–Fischer algorithm. +// Simple implementation of the Wagner-Fischer algorithm. // See http://en.wikipedia.org/wiki/Wagner-Fischer_algorithm enum EditType { kMatch, kAdd, kRemove, kReplace }; GTEST_API_ std::vector<EditType> CalculateOptimalEdits( @@ -502,9 +490,10 @@ typedef void (*SetUpTestCaseFunc)(); typedef void (*TearDownTestCaseFunc)(); struct CodeLocation { - CodeLocation(const string& a_file, int a_line) : file(a_file), line(a_line) {} + CodeLocation(const std::string& a_file, int a_line) + : file(a_file), line(a_line) {} - string file; + std::string file; int line; }; @@ -544,6 +533,9 @@ GTEST_API_ bool SkipPrefix(const char* prefix, const char** pstr); #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + // State of the definition of a type-parameterized test case. class GTEST_API_ TypedTestCasePState { public: @@ -589,6 +581,8 @@ class GTEST_API_ TypedTestCasePState { RegisteredTestsMap registered_tests_; }; +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + // Skips to the first non-space char after the first comma in 'str'; // returns NULL if no comma is found in 'str'. inline const char* SkipComma(const char* str) { @@ -612,6 +606,37 @@ inline std::string GetPrefixUntilComma(const char* str) { void SplitString(const ::std::string& str, char delimiter, ::std::vector< ::std::string>* dest); +// The default argument to the template below for the case when the user does +// not provide a name generator. +struct DefaultNameGenerator { + template <typename T> + static std::string GetName(int i) { + return StreamableToString(i); + } +}; + +template <typename Provided = DefaultNameGenerator> +struct NameGeneratorSelector { + typedef Provided type; +}; + +template <typename NameGenerator> +void GenerateNamesRecursively(Types0, std::vector<std::string>*, int) {} + +template <typename NameGenerator, typename Types> +void GenerateNamesRecursively(Types, std::vector<std::string>* result, int i) { + result->push_back(NameGenerator::template GetName<typename Types::Head>(i)); + GenerateNamesRecursively<NameGenerator>(typename Types::Tail(), result, + i + 1); +} + +template <typename NameGenerator, typename Types> +std::vector<std::string> GenerateNames() { + std::vector<std::string> result; + GenerateNamesRecursively<NameGenerator>(Types(), &result, 0); + return result; +} + // TypeParameterizedTest<Fixture, TestSel, Types>::Register() // registers a list of type-parameterized tests with Google Test. The // return value is insignificant - we just need to return something @@ -626,10 +651,10 @@ class TypeParameterizedTest { // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase, // Types). Valid values for 'index' are [0, N - 1] where N is the // length of Types. - static bool Register(const char* prefix, - CodeLocation code_location, - const char* case_name, const char* test_names, - int index) { + static bool Register(const char* prefix, const CodeLocation& code_location, + const char* case_name, const char* test_names, int index, + const std::vector<std::string>& type_names = + GenerateNames<DefaultNameGenerator, Types>()) { typedef typename Types::Head Type; typedef Fixture<Type> FixtureClass; typedef typename GTEST_BIND_(TestSel, Type) TestClass; @@ -637,20 +662,23 @@ class TypeParameterizedTest { // First, registers the first type-parameterized test in the type // list. MakeAndRegisterTestInfo( - (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + "/" - + StreamableToString(index)).c_str(), + (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + + "/" + type_names[index]) + .c_str(), StripTrailingSpaces(GetPrefixUntilComma(test_names)).c_str(), GetTypeName<Type>().c_str(), NULL, // No value parameter. - code_location, - GetTypeId<FixtureClass>(), - TestClass::SetUpTestCase, - TestClass::TearDownTestCase, - new TestFactoryImpl<TestClass>); + code_location, GetTypeId<FixtureClass>(), TestClass::SetUpTestCase, + TestClass::TearDownTestCase, new TestFactoryImpl<TestClass>); // Next, recurses (at compile time) with the tail of the type list. - return TypeParameterizedTest<Fixture, TestSel, typename Types::Tail> - ::Register(prefix, code_location, case_name, test_names, index + 1); + return TypeParameterizedTest<Fixture, TestSel, + typename Types::Tail>::Register(prefix, + code_location, + case_name, + test_names, + index + 1, + type_names); } }; @@ -658,9 +686,11 @@ class TypeParameterizedTest { template <GTEST_TEMPLATE_ Fixture, class TestSel> class TypeParameterizedTest<Fixture, TestSel, Types0> { public: - static bool Register(const char* /*prefix*/, CodeLocation, + static bool Register(const char* /*prefix*/, const CodeLocation&, const char* /*case_name*/, const char* /*test_names*/, - int /*index*/) { + int /*index*/, + const std::vector<std::string>& = + std::vector<std::string>() /*type_names*/) { return true; } }; @@ -673,8 +703,10 @@ template <GTEST_TEMPLATE_ Fixture, typename Tests, typename Types> class TypeParameterizedTestCase { public: static bool Register(const char* prefix, CodeLocation code_location, - const TypedTestCasePState* state, - const char* case_name, const char* test_names) { + const TypedTestCasePState* state, const char* case_name, + const char* test_names, + const std::vector<std::string>& type_names = + GenerateNames<DefaultNameGenerator, Types>()) { std::string test_name = StripTrailingSpaces( GetPrefixUntilComma(test_names)); if (!state->TestExists(test_name)) { @@ -691,12 +723,14 @@ class TypeParameterizedTestCase { // First, register the first test in 'Test' for each type in 'Types'. TypeParameterizedTest<Fixture, Head, Types>::Register( - prefix, test_location, case_name, test_names, 0); + prefix, test_location, case_name, test_names, 0, type_names); // Next, recurses (at compile time) with the tail of the test list. - return TypeParameterizedTestCase<Fixture, typename Tests::Tail, Types> - ::Register(prefix, code_location, state, - case_name, SkipComma(test_names)); + return TypeParameterizedTestCase<Fixture, typename Tests::Tail, + Types>::Register(prefix, code_location, + state, case_name, + SkipComma(test_names), + type_names); } }; @@ -704,9 +738,11 @@ class TypeParameterizedTestCase { template <GTEST_TEMPLATE_ Fixture, typename Types> class TypeParameterizedTestCase<Fixture, Templates0, Types> { public: - static bool Register(const char* /*prefix*/, CodeLocation, + static bool Register(const char* /*prefix*/, const CodeLocation&, const TypedTestCasePState* /*state*/, - const char* /*case_name*/, const char* /*test_names*/) { + const char* /*case_name*/, const char* /*test_names*/, + const std::vector<std::string>& = + std::vector<std::string>() /*type_names*/) { return true; } }; @@ -823,31 +859,6 @@ struct RemoveConst<T[N]> { #define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \ GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T)) -// Adds reference to a type if it is not a reference type, -// otherwise leaves it unchanged. This is the same as -// tr1::add_reference, which is not widely available yet. -template <typename T> -struct AddReference { typedef T& type; }; // NOLINT -template <typename T> -struct AddReference<T&> { typedef T& type; }; // NOLINT - -// A handy wrapper around AddReference that works when the argument T -// depends on template parameters. -#define GTEST_ADD_REFERENCE_(T) \ - typename ::testing::internal::AddReference<T>::type - -// Adds a reference to const on top of T as necessary. For example, -// it transforms -// -// char ==> const char& -// const char ==> const char& -// char& ==> const char& -// const char& ==> const char& -// -// The argument T must depend on some template parameters. -#define GTEST_REFERENCE_TO_CONST_(T) \ - GTEST_ADD_REFERENCE_(const GTEST_REMOVE_REFERENCE_(T)) - // ImplicitlyConvertible<From, To>::value is a compile-time bool // constant that's true iff type From can be implicitly converted to // type To. @@ -917,8 +928,11 @@ struct IsAProtocolMessage // a container class by checking the type of IsContainerTest<C>(0). // The value of the expression is insignificant. // -// Note that we look for both C::iterator and C::const_iterator. The -// reason is that C++ injects the name of a class as a member of the +// In C++11 mode we check the existence of a const_iterator and that an +// iterator is properly implemented for the container. +// +// For pre-C++11 that we look for both C::iterator and C::const_iterator. +// The reason is that C++ injects the name of a class as a member of the // class itself (e.g. you can refer to class iterator as either // 'iterator' or 'iterator::iterator'). If we look for C::iterator // only, for example, we would mistakenly think that a class named @@ -928,17 +942,96 @@ struct IsAProtocolMessage // IsContainerTest(typename C::const_iterator*) and // IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++. typedef int IsContainer; +#if GTEST_LANG_CXX11 +template <class C, + class Iterator = decltype(::std::declval<const C&>().begin()), + class = decltype(::std::declval<const C&>().end()), + class = decltype(++::std::declval<Iterator&>()), + class = decltype(*::std::declval<Iterator>()), + class = typename C::const_iterator> +IsContainer IsContainerTest(int /* dummy */) { + return 0; +} +#else template <class C> IsContainer IsContainerTest(int /* dummy */, typename C::iterator* /* it */ = NULL, typename C::const_iterator* /* const_it */ = NULL) { return 0; } +#endif // GTEST_LANG_CXX11 typedef char IsNotContainer; template <class C> IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; } +// Trait to detect whether a type T is a hash table. +// The heuristic used is that the type contains an inner type `hasher` and does +// not contain an inner type `reverse_iterator`. +// If the container is iterable in reverse, then order might actually matter. +template <typename T> +struct IsHashTable { + private: + template <typename U> + static char test(typename U::hasher*, typename U::reverse_iterator*); + template <typename U> + static int test(typename U::hasher*, ...); + template <typename U> + static char test(...); + + public: + static const bool value = sizeof(test<T>(0, 0)) == sizeof(int); +}; + +template <typename T> +const bool IsHashTable<T>::value; + +template<typename T> +struct VoidT { + typedef void value_type; +}; + +template <typename T, typename = void> +struct HasValueType : false_type {}; +template <typename T> +struct HasValueType<T, VoidT<typename T::value_type> > : true_type { +}; + +template <typename C, + bool = sizeof(IsContainerTest<C>(0)) == sizeof(IsContainer), + bool = HasValueType<C>::value> +struct IsRecursiveContainerImpl; + +template <typename C, bool HV> +struct IsRecursiveContainerImpl<C, false, HV> : public false_type {}; + +// Since the IsRecursiveContainerImpl depends on the IsContainerTest we need to +// obey the same inconsistencies as the IsContainerTest, namely check if +// something is a container is relying on only const_iterator in C++11 and +// is relying on both const_iterator and iterator otherwise +template <typename C> +struct IsRecursiveContainerImpl<C, true, false> : public false_type {}; + +template <typename C> +struct IsRecursiveContainerImpl<C, true, true> { + #if GTEST_LANG_CXX11 + typedef typename IteratorTraits<typename C::const_iterator>::value_type + value_type; +#else + typedef typename IteratorTraits<typename C::iterator>::value_type value_type; +#endif + typedef is_same<value_type, C> type; +}; + +// IsRecursiveContainer<Type> is a unary compile-time predicate that +// evaluates whether C is a recursive container type. A recursive container +// type is a container type whose value_type is equal to the container type +// itself. An example for a recursive container type is +// boost::filesystem::path, whose iterator has a value_type that is equal to +// boost::filesystem::path. +template <typename C> +struct IsRecursiveContainer : public IsRecursiveContainerImpl<C>::type {}; + // EnableIf<condition>::type is void when 'Cond' is true, and // undefined when 'Cond' is false. To use SFINAE to make a function // overload only apply when a particular expression is true, add @@ -1070,7 +1163,7 @@ class NativeArray { private: enum { kCheckTypeIsNotConstOrAReference = StaticAssertTypeEqHelper< - Element, GTEST_REMOVE_REFERENCE_AND_CONST_(Element)>::value, + Element, GTEST_REMOVE_REFERENCE_AND_CONST_(Element)>::value }; // Initializes this object with a copy of the input. @@ -1115,7 +1208,7 @@ class NativeArray { #define GTEST_SUCCESS_(message) \ GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess) -// Suppresses MSVC warnings 4072 (unreachable code) for the code following +// Suppress MSVC warning 4702 (unreachable code) for the code following // statement if it returns or throws (or doesn't return or throw in some // situations). #define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \ @@ -1235,4 +1328,3 @@ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ - diff --git a/test/googletest/include/gtest/internal/gtest-linked_ptr.h b/test/googletest/include/gtest/internal/gtest-linked_ptr.h index 36029422..082b8728 100644 --- a/test/googletest/include/gtest/internal/gtest-linked_ptr.h +++ b/test/googletest/include/gtest/internal/gtest-linked_ptr.h @@ -27,8 +27,6 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: Dan Egnor (egnor@google.com) -// // A "smart" pointer type with reference tracking. Every pointer to a // particular object is kept on a circular linked list. When the last pointer // to an object is destroyed or reassigned, the object is deleted. @@ -62,9 +60,11 @@ // raw pointer (e.g. via get()) concurrently, and // - it's safe to write to two linked_ptrs that point to the same // shared object concurrently. -// TODO(wan@google.com): rename this to safe_linked_ptr to avoid +// FIXME: rename this to safe_linked_ptr to avoid // confusion with normal linked_ptr. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ diff --git a/test/googletest/include/gtest/internal/gtest-param-util-generated.h b/test/googletest/include/gtest/internal/gtest-param-util-generated.h index 4d1d81d2..4fac8c02 100644 --- a/test/googletest/include/gtest/internal/gtest-param-util-generated.h +++ b/test/googletest/include/gtest/internal/gtest-param-util-generated.h @@ -30,8 +30,7 @@ // 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. -// -// Author: vladl@google.com (Vlad Losev) + // Type and function utilities for implementing parameterized tests. // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! @@ -43,17 +42,14 @@ // by the maximum arity of the implementation of tuple which is // currently set at 10. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. #include "gtest/internal/gtest-param-util.h" #include "gtest/internal/gtest-port.h" -#if GTEST_HAS_PARAM_TEST - namespace testing { // Forward declarations of ValuesIn(), which is implemented in @@ -84,6 +80,8 @@ class ValueArray1 { return ValuesIn(array); } + ValueArray1(const ValueArray1& other) : v1_(other.v1_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray1& other); @@ -102,6 +100,8 @@ class ValueArray2 { return ValuesIn(array); } + ValueArray2(const ValueArray2& other) : v1_(other.v1_), v2_(other.v2_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray2& other); @@ -122,6 +122,9 @@ class ValueArray3 { return ValuesIn(array); } + ValueArray3(const ValueArray3& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray3& other); @@ -144,6 +147,9 @@ class ValueArray4 { return ValuesIn(array); } + ValueArray4(const ValueArray4& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray4& other); @@ -167,6 +173,9 @@ class ValueArray5 { return ValuesIn(array); } + ValueArray5(const ValueArray5& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray5& other); @@ -193,6 +202,9 @@ class ValueArray6 { return ValuesIn(array); } + ValueArray6(const ValueArray6& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray6& other); @@ -220,6 +232,10 @@ class ValueArray7 { return ValuesIn(array); } + ValueArray7(const ValueArray7& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray7& other); @@ -249,6 +265,10 @@ class ValueArray8 { return ValuesIn(array); } + ValueArray8(const ValueArray8& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray8& other); @@ -280,6 +300,10 @@ class ValueArray9 { return ValuesIn(array); } + ValueArray9(const ValueArray9& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray9& other); @@ -312,6 +336,10 @@ class ValueArray10 { return ValuesIn(array); } + ValueArray10(const ValueArray10& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray10& other); @@ -346,6 +374,11 @@ class ValueArray11 { return ValuesIn(array); } + ValueArray11(const ValueArray11& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray11& other); @@ -382,6 +415,11 @@ class ValueArray12 { return ValuesIn(array); } + ValueArray12(const ValueArray12& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray12& other); @@ -420,6 +458,11 @@ class ValueArray13 { return ValuesIn(array); } + ValueArray13(const ValueArray13& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray13& other); @@ -459,6 +502,11 @@ class ValueArray14 { return ValuesIn(array); } + ValueArray14(const ValueArray14& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray14& other); @@ -500,6 +548,12 @@ class ValueArray15 { return ValuesIn(array); } + ValueArray15(const ValueArray15& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray15& other); @@ -544,6 +598,12 @@ class ValueArray16 { return ValuesIn(array); } + ValueArray16(const ValueArray16& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray16& other); @@ -589,6 +649,12 @@ class ValueArray17 { return ValuesIn(array); } + ValueArray17(const ValueArray17& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray17& other); @@ -636,6 +702,12 @@ class ValueArray18 { return ValuesIn(array); } + ValueArray18(const ValueArray18& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray18& other); @@ -684,6 +756,13 @@ class ValueArray19 { return ValuesIn(array); } + ValueArray19(const ValueArray19& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray19& other); @@ -734,6 +813,13 @@ class ValueArray20 { return ValuesIn(array); } + ValueArray20(const ValueArray20& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray20& other); @@ -787,6 +873,13 @@ class ValueArray21 { return ValuesIn(array); } + ValueArray21(const ValueArray21& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray21& other); @@ -841,6 +934,13 @@ class ValueArray22 { return ValuesIn(array); } + ValueArray22(const ValueArray22& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray22& other); @@ -897,6 +997,14 @@ class ValueArray23 { return ValuesIn(array); } + ValueArray23(const ValueArray23& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray23& other); @@ -955,6 +1063,14 @@ class ValueArray24 { return ValuesIn(array); } + ValueArray24(const ValueArray24& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray24& other); @@ -1014,6 +1130,14 @@ class ValueArray25 { return ValuesIn(array); } + ValueArray25(const ValueArray25& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray25& other); @@ -1075,6 +1199,14 @@ class ValueArray26 { return ValuesIn(array); } + ValueArray26(const ValueArray26& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray26& other); @@ -1139,6 +1271,15 @@ class ValueArray27 { return ValuesIn(array); } + ValueArray27(const ValueArray27& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray27& other); @@ -1204,6 +1345,15 @@ class ValueArray28 { return ValuesIn(array); } + ValueArray28(const ValueArray28& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray28& other); @@ -1270,6 +1420,15 @@ class ValueArray29 { return ValuesIn(array); } + ValueArray29(const ValueArray29& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray29& other); @@ -1339,6 +1498,15 @@ class ValueArray30 { return ValuesIn(array); } + ValueArray30(const ValueArray30& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray30& other); @@ -1410,6 +1578,16 @@ class ValueArray31 { return ValuesIn(array); } + ValueArray31(const ValueArray31& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray31& other); @@ -1482,6 +1660,16 @@ class ValueArray32 { return ValuesIn(array); } + ValueArray32(const ValueArray32& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray32& other); @@ -1557,6 +1745,16 @@ class ValueArray33 { return ValuesIn(array); } + ValueArray33(const ValueArray33& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray33& other); @@ -1633,6 +1831,16 @@ class ValueArray34 { return ValuesIn(array); } + ValueArray34(const ValueArray34& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray34& other); @@ -1710,6 +1918,17 @@ class ValueArray35 { return ValuesIn(array); } + ValueArray35(const ValueArray35& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray35& other); @@ -1790,6 +2009,17 @@ class ValueArray36 { return ValuesIn(array); } + ValueArray36(const ValueArray36& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray36& other); @@ -1872,6 +2102,17 @@ class ValueArray37 { return ValuesIn(array); } + ValueArray37(const ValueArray37& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray37& other); @@ -1955,6 +2196,17 @@ class ValueArray38 { return ValuesIn(array); } + ValueArray38(const ValueArray38& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray38& other); @@ -2040,6 +2292,18 @@ class ValueArray39 { return ValuesIn(array); } + ValueArray39(const ValueArray39& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray39& other); @@ -2127,6 +2391,18 @@ class ValueArray40 { return ValuesIn(array); } + ValueArray40(const ValueArray40& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray40& other); @@ -2216,6 +2492,18 @@ class ValueArray41 { return ValuesIn(array); } + ValueArray41(const ValueArray41& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray41& other); @@ -2307,6 +2595,18 @@ class ValueArray42 { return ValuesIn(array); } + ValueArray42(const ValueArray42& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray42& other); @@ -2399,6 +2699,19 @@ class ValueArray43 { return ValuesIn(array); } + ValueArray43(const ValueArray43& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), + v43_(other.v43_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray43& other); @@ -2493,6 +2806,19 @@ class ValueArray44 { return ValuesIn(array); } + ValueArray44(const ValueArray44& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), + v43_(other.v43_), v44_(other.v44_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray44& other); @@ -2589,6 +2915,19 @@ class ValueArray45 { return ValuesIn(array); } + ValueArray45(const ValueArray45& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), + v43_(other.v43_), v44_(other.v44_), v45_(other.v45_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray45& other); @@ -2687,6 +3026,19 @@ class ValueArray46 { return ValuesIn(array); } + ValueArray46(const ValueArray46& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), + v43_(other.v43_), v44_(other.v44_), v45_(other.v45_), v46_(other.v46_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray46& other); @@ -2787,6 +3139,20 @@ class ValueArray47 { return ValuesIn(array); } + ValueArray47(const ValueArray47& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), + v43_(other.v43_), v44_(other.v44_), v45_(other.v45_), v46_(other.v46_), + v47_(other.v47_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray47& other); @@ -2889,6 +3255,20 @@ class ValueArray48 { return ValuesIn(array); } + ValueArray48(const ValueArray48& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), + v43_(other.v43_), v44_(other.v44_), v45_(other.v45_), v46_(other.v46_), + v47_(other.v47_), v48_(other.v48_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray48& other); @@ -2992,6 +3372,20 @@ class ValueArray49 { return ValuesIn(array); } + ValueArray49(const ValueArray49& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), + v43_(other.v43_), v44_(other.v44_), v45_(other.v45_), v46_(other.v46_), + v47_(other.v47_), v48_(other.v48_), v49_(other.v49_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray49& other); @@ -3096,6 +3490,20 @@ class ValueArray50 { return ValuesIn(array); } + ValueArray50(const ValueArray50& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), + v43_(other.v43_), v44_(other.v44_), v45_(other.v45_), v46_(other.v46_), + v47_(other.v47_), v48_(other.v48_), v49_(other.v49_), v50_(other.v50_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray50& other); @@ -3208,7 +3616,7 @@ class CartesianProductGenerator2 virtual ParamIteratorInterface<ParamType>* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -3240,7 +3648,7 @@ class CartesianProductGenerator2 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_); + current_value_.reset(new ParamType(*current1_, *current2_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -3262,7 +3670,7 @@ class CartesianProductGenerator2 const typename ParamGenerator<T2>::iterator begin2_; const typename ParamGenerator<T2>::iterator end2_; typename ParamGenerator<T2>::iterator current2_; - ParamType current_value_; + linked_ptr<ParamType> current_value_; }; // class CartesianProductGenerator2::Iterator // No implementation - assignment is unsupported. @@ -3331,7 +3739,7 @@ class CartesianProductGenerator3 virtual ParamIteratorInterface<ParamType>* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -3367,7 +3775,7 @@ class CartesianProductGenerator3 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -3393,7 +3801,7 @@ class CartesianProductGenerator3 const typename ParamGenerator<T3>::iterator begin3_; const typename ParamGenerator<T3>::iterator end3_; typename ParamGenerator<T3>::iterator current3_; - ParamType current_value_; + linked_ptr<ParamType> current_value_; }; // class CartesianProductGenerator3::Iterator // No implementation - assignment is unsupported. @@ -3472,7 +3880,7 @@ class CartesianProductGenerator4 virtual ParamIteratorInterface<ParamType>* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -3512,8 +3920,8 @@ class CartesianProductGenerator4 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, + *current4_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -3543,7 +3951,7 @@ class CartesianProductGenerator4 const typename ParamGenerator<T4>::iterator begin4_; const typename ParamGenerator<T4>::iterator end4_; typename ParamGenerator<T4>::iterator current4_; - ParamType current_value_; + linked_ptr<ParamType> current_value_; }; // class CartesianProductGenerator4::Iterator // No implementation - assignment is unsupported. @@ -3630,7 +4038,7 @@ class CartesianProductGenerator5 virtual ParamIteratorInterface<ParamType>* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -3674,8 +4082,8 @@ class CartesianProductGenerator5 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -3709,7 +4117,7 @@ class CartesianProductGenerator5 const typename ParamGenerator<T5>::iterator begin5_; const typename ParamGenerator<T5>::iterator end5_; typename ParamGenerator<T5>::iterator current5_; - ParamType current_value_; + linked_ptr<ParamType> current_value_; }; // class CartesianProductGenerator5::Iterator // No implementation - assignment is unsupported. @@ -3807,7 +4215,7 @@ class CartesianProductGenerator6 virtual ParamIteratorInterface<ParamType>* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -3855,8 +4263,8 @@ class CartesianProductGenerator6 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -3894,7 +4302,7 @@ class CartesianProductGenerator6 const typename ParamGenerator<T6>::iterator begin6_; const typename ParamGenerator<T6>::iterator end6_; typename ParamGenerator<T6>::iterator current6_; - ParamType current_value_; + linked_ptr<ParamType> current_value_; }; // class CartesianProductGenerator6::Iterator // No implementation - assignment is unsupported. @@ -4001,7 +4409,7 @@ class CartesianProductGenerator7 virtual ParamIteratorInterface<ParamType>* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -4053,8 +4461,8 @@ class CartesianProductGenerator7 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_, *current7_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -4096,7 +4504,7 @@ class CartesianProductGenerator7 const typename ParamGenerator<T7>::iterator begin7_; const typename ParamGenerator<T7>::iterator end7_; typename ParamGenerator<T7>::iterator current7_; - ParamType current_value_; + linked_ptr<ParamType> current_value_; }; // class CartesianProductGenerator7::Iterator // No implementation - assignment is unsupported. @@ -4214,7 +4622,7 @@ class CartesianProductGenerator8 virtual ParamIteratorInterface<ParamType>* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -4270,8 +4678,8 @@ class CartesianProductGenerator8 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_, *current7_, *current8_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_, *current8_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -4317,7 +4725,7 @@ class CartesianProductGenerator8 const typename ParamGenerator<T8>::iterator begin8_; const typename ParamGenerator<T8>::iterator end8_; typename ParamGenerator<T8>::iterator current8_; - ParamType current_value_; + linked_ptr<ParamType> current_value_; }; // class CartesianProductGenerator8::Iterator // No implementation - assignment is unsupported. @@ -4443,7 +4851,7 @@ class CartesianProductGenerator9 virtual ParamIteratorInterface<ParamType>* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -4503,9 +4911,9 @@ class CartesianProductGenerator9 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_, *current8_, - *current9_); + *current9_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -4555,7 +4963,7 @@ class CartesianProductGenerator9 const typename ParamGenerator<T9>::iterator begin9_; const typename ParamGenerator<T9>::iterator end9_; typename ParamGenerator<T9>::iterator current9_; - ParamType current_value_; + linked_ptr<ParamType> current_value_; }; // class CartesianProductGenerator9::Iterator // No implementation - assignment is unsupported. @@ -4690,7 +5098,7 @@ class CartesianProductGenerator10 virtual ParamIteratorInterface<ParamType>* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -4754,9 +5162,9 @@ class CartesianProductGenerator10 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_, *current8_, - *current9_, *current10_); + *current9_, *current10_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -4810,7 +5218,7 @@ class CartesianProductGenerator10 const typename ParamGenerator<T10>::iterator begin10_; const typename ParamGenerator<T10>::iterator end10_; typename ParamGenerator<T10>::iterator current10_; - ParamType current_value_; + linked_ptr<ParamType> current_value_; }; // class CartesianProductGenerator10::Iterator // No implementation - assignment is unsupported. @@ -5141,6 +5549,4 @@ CartesianProductHolder10(const Generator1& g1, const Generator2& g2, } // namespace internal } // namespace testing -#endif // GTEST_HAS_PARAM_TEST - #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ diff --git a/test/googletest/include/gtest/internal/gtest-param-util-generated.h.pump b/test/googletest/include/gtest/internal/gtest-param-util-generated.h.pump index 5c7c47af..30dffe43 100644 --- a/test/googletest/include/gtest/internal/gtest-param-util-generated.h.pump +++ b/test/googletest/include/gtest/internal/gtest-param-util-generated.h.pump @@ -29,8 +29,7 @@ $var maxtuple = 10 $$ Maximum number of Combine arguments we want to support. // 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. -// -// Author: vladl@google.com (Vlad Losev) + // Type and function utilities for implementing parameterized tests. // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! @@ -42,17 +41,14 @@ $var maxtuple = 10 $$ Maximum number of Combine arguments we want to support. // by the maximum arity of the implementation of tuple which is // currently set at $maxtuple. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. #include "gtest/internal/gtest-param-util.h" #include "gtest/internal/gtest-port.h" -#if GTEST_HAS_PARAM_TEST - namespace testing { // Forward declarations of ValuesIn(), which is implemented in @@ -87,6 +83,8 @@ class ValueArray$i { return ValuesIn(array); } + ValueArray$i(const ValueArray$i& other) : $for j, [[v$(j)_(other.v$(j)_)]] {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray$i& other); @@ -165,7 +163,7 @@ $for k [[ virtual ParamIteratorInterface<ParamType>* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -197,7 +195,7 @@ $for k [[ void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType($for j, [[*current$(j)_]]); + current_value_.reset(new ParamType($for j, [[*current$(j)_]])); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -222,7 +220,7 @@ $for j [[ typename ParamGenerator<T$j>::iterator current$(j)_; ]] - ParamType current_value_; + linked_ptr<ParamType> current_value_; }; // class CartesianProductGenerator$i::Iterator // No implementation - assignment is unsupported. @@ -281,6 +279,4 @@ $for j [[ } // namespace internal } // namespace testing -#endif // GTEST_HAS_PARAM_TEST - #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ diff --git a/test/googletest/include/gtest/internal/gtest-param-util.h b/test/googletest/include/gtest/internal/gtest-param-util.h index 82cab9b0..d64f620c 100644 --- a/test/googletest/include/gtest/internal/gtest-param-util.h +++ b/test/googletest/include/gtest/internal/gtest-param-util.h @@ -26,11 +26,12 @@ // 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. -// -// Author: vladl@google.com (Vlad Losev) + // Type and function utilities for implementing parameterized tests. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ @@ -41,16 +42,11 @@ #include <utility> #include <vector> -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-linked_ptr.h" #include "gtest/internal/gtest-port.h" #include "gtest/gtest-printers.h" -#if GTEST_HAS_PARAM_TEST - namespace testing { // Input to a parameterized test name generator, describing a test parameter. @@ -472,7 +468,7 @@ class ParameterizedTestCaseInfoBase { virtual ~ParameterizedTestCaseInfoBase() {} // Base part of test case name for display purposes. - virtual const string& GetTestCaseName() const = 0; + virtual const std::string& GetTestCaseName() const = 0; // Test case id to verify identity. virtual TypeId GetTestCaseTypeId() const = 0; // UnitTest class invokes this method to register tests in this @@ -511,7 +507,7 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { : test_case_name_(name), code_location_(code_location) {} // Test case base name for display purposes. - virtual const string& GetTestCaseName() const { return test_case_name_; } + virtual const std::string& GetTestCaseName() const { return test_case_name_; } // Test case id to verify identity. virtual TypeId GetTestCaseTypeId() const { return GetTypeId<TestCase>(); } // TEST_P macro uses AddTestPattern() to record information @@ -529,11 +525,10 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { } // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information // about a generator. - int AddTestCaseInstantiation(const string& instantiation_name, + int AddTestCaseInstantiation(const std::string& instantiation_name, GeneratorCreationFunc* func, ParamNameGeneratorFunc* name_func, - const char* file, - int line) { + const char* file, int line) { instantiations_.push_back( InstantiationInfo(instantiation_name, func, name_func, file, line)); return 0; // Return value used only to run this method in namespace scope. @@ -550,13 +545,13 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { for (typename InstantiationContainer::iterator gen_it = instantiations_.begin(); gen_it != instantiations_.end(); ++gen_it) { - const string& instantiation_name = gen_it->name; + const std::string& instantiation_name = gen_it->name; ParamGenerator<ParamType> generator((*gen_it->generator)()); ParamNameGeneratorFunc* name_func = gen_it->name_func; const char* file = gen_it->file; int line = gen_it->line; - string test_case_name; + std::string test_case_name; if ( !instantiation_name.empty() ) test_case_name = instantiation_name + "/"; test_case_name += test_info->test_case_base_name; @@ -609,8 +604,8 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { test_base_name(a_test_base_name), test_meta_factory(a_test_meta_factory) {} - const string test_case_base_name; - const string test_base_name; + const std::string test_case_base_name; + const std::string test_base_name; const scoped_ptr<TestMetaFactoryBase<ParamType> > test_meta_factory; }; typedef ::std::vector<linked_ptr<TestInfo> > TestInfoContainer; @@ -651,7 +646,7 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { return true; } - const string test_case_name_; + const std::string test_case_name_; CodeLocation code_location_; TestInfoContainer tests_; InstantiationContainer instantiations_; @@ -726,6 +721,4 @@ class ParameterizedTestCaseRegistry { } // namespace internal } // namespace testing -#endif // GTEST_HAS_PARAM_TEST - #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ diff --git a/test/googletest/include/gtest/internal/gtest-port-arch.h b/test/googletest/include/gtest/internal/gtest-port-arch.h index 74ab9490..f83700e0 100644 --- a/test/googletest/include/gtest/internal/gtest-port-arch.h +++ b/test/googletest/include/gtest/internal/gtest-port-arch.h @@ -27,7 +27,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file defines the GTEST_OS_* macro. // It is separate from gtest-port.h so that custom/gtest-port.h can include it. @@ -54,6 +54,9 @@ # define GTEST_OS_WINDOWS_PHONE 1 # elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) # define GTEST_OS_WINDOWS_RT 1 +# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_TV_TITLE) +# define GTEST_OS_WINDOWS_PHONE 1 +# define GTEST_OS_WINDOWS_TV_TITLE 1 # else // WINAPI_FAMILY defined but no known partition matched. // Default to desktop. @@ -69,6 +72,8 @@ # endif #elif defined __FreeBSD__ # define GTEST_OS_FREEBSD 1 +#elif defined __Fuchsia__ +# define GTEST_OS_FUCHSIA 1 #elif defined __linux__ # define GTEST_OS_LINUX 1 # if defined __ANDROID__ @@ -84,6 +89,8 @@ # define GTEST_OS_HPUX 1 #elif defined __native_client__ # define GTEST_OS_NACL 1 +#elif defined __NetBSD__ +# define GTEST_OS_NETBSD 1 #elif defined __OpenBSD__ # define GTEST_OS_OPENBSD 1 #elif defined __QNX__ diff --git a/test/googletest/include/gtest/internal/gtest-port.h b/test/googletest/include/gtest/internal/gtest-port.h index 0094ed50..786497d8 100644 --- a/test/googletest/include/gtest/internal/gtest-port.h +++ b/test/googletest/include/gtest/internal/gtest-port.h @@ -27,8 +27,6 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: wan@google.com (Zhanyong Wan) -// // Low-level types and utilities for porting Google Test to various // platforms. All macros ending with _ and symbols defined in an // internal namespace are subject to change without notice. Code @@ -40,6 +38,8 @@ // files are expected to #include this. Therefore, it cannot #include // any other Google Test header. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ @@ -73,11 +73,9 @@ // GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions // are enabled. // GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string -// is/isn't available (some systems define -// ::string, which is different to std::string). -// GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string -// is/isn't available (some systems define -// ::wstring, which is different to std::wstring). +// is/isn't available +// GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::wstring +// is/isn't available // GTEST_HAS_POSIX_RE - Define it to 1/0 to indicate that POSIX regular // expressions are/aren't available. // GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that <pthread.h> @@ -109,6 +107,12 @@ // GTEST_CREATE_SHARED_LIBRARY // - Define to 1 when compiling Google Test itself // as a shared library. +// GTEST_DEFAULT_DEATH_TEST_STYLE +// - The default value of --gtest_death_test_style. +// The legacy default has been "fast" in the open +// source version since 2008. The recommended value +// is "threadsafe", and can be set in +// custom/gtest-port.h. // Platform-indicating macros // -------------------------- @@ -122,12 +126,14 @@ // GTEST_OS_AIX - IBM AIX // GTEST_OS_CYGWIN - Cygwin // GTEST_OS_FREEBSD - FreeBSD +// GTEST_OS_FUCHSIA - Fuchsia // GTEST_OS_HPUX - HP-UX // GTEST_OS_LINUX - Linux // GTEST_OS_LINUX_ANDROID - Google Android // GTEST_OS_MAC - Mac OS X // GTEST_OS_IOS - iOS // GTEST_OS_NACL - Google Native Client (NaCl) +// GTEST_OS_NETBSD - NetBSD // GTEST_OS_OPENBSD - OpenBSD // GTEST_OS_QNX - QNX // GTEST_OS_SOLARIS - Sun Solaris @@ -169,15 +175,15 @@ // GTEST_HAS_COMBINE - the Combine() function (for value-parameterized // tests) // GTEST_HAS_DEATH_TEST - death tests -// GTEST_HAS_PARAM_TEST - value-parameterized tests // GTEST_HAS_TYPED_TEST - typed tests // GTEST_HAS_TYPED_TEST_P - type-parameterized tests // GTEST_IS_THREADSAFE - Google Test is thread-safe. +// GOOGLETEST_CM0007 DO NOT DELETE // GTEST_USES_POSIX_RE - enhanced POSIX regex is used. Do not confuse with // GTEST_HAS_POSIX_RE (see above) which users can // define themselves. // GTEST_USES_SIMPLE_RE - our own simple regex is used; -// the above two are mutually exclusive. +// the above RE\b(s) are mutually exclusive. // GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ(). // Misc public macros @@ -206,6 +212,7 @@ // // C++11 feature wrappers: // +// testing::internal::forward - portability wrapper for std::forward. // testing::internal::move - portability wrapper for std::move. // // Synchronization: @@ -222,10 +229,10 @@ // // Regular expressions: // RE - a simple regular expression class using the POSIX -// Extended Regular Expression syntax on UNIX-like -// platforms, or a reduced regular exception syntax on -// other platforms, including Windows. -// +// Extended Regular Expression syntax on UNIX-like platforms +// GOOGLETEST_CM0008 DO NOT DELETE +// or a reduced regular exception syntax on other +// platforms, including Windows. // Logging: // GTEST_LOG_() - logs messages at the specified severity level. // LogToStderr() - directs all log messages to stderr. @@ -271,10 +278,12 @@ # include <TargetConditionals.h> #endif +// Brings in the definition of HAS_GLOBAL_STRING. This must be done +// BEFORE we test HAS_GLOBAL_STRING. +#include <string> // NOLINT #include <algorithm> // NOLINT #include <iostream> // NOLINT #include <sstream> // NOLINT -#include <string> // NOLINT #include <utility> #include <vector> // NOLINT @@ -306,7 +315,7 @@ // GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 4385) // /* code that triggers warnings C4800 and C4385 */ // GTEST_DISABLE_MSC_WARNINGS_POP_() -#if _MSC_VER >= 1500 +#if _MSC_VER >= 1400 # define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) \ __pragma(warning(push)) \ __pragma(warning(disable: warnings)) @@ -318,12 +327,28 @@ # define GTEST_DISABLE_MSC_WARNINGS_POP_() #endif +// Clang on Windows does not understand MSVC's pragma warning. +// We need clang-specific way to disable function deprecation warning. +#ifdef __clang__ +# define GTEST_DISABLE_MSC_DEPRECATED_PUSH_() \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") \ + _Pragma("clang diagnostic ignored \"-Wdeprecated-implementations\"") +#define GTEST_DISABLE_MSC_DEPRECATED_POP_() \ + _Pragma("clang diagnostic pop") +#else +# define GTEST_DISABLE_MSC_DEPRECATED_PUSH_() \ + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996) +# define GTEST_DISABLE_MSC_DEPRECATED_POP_() \ + GTEST_DISABLE_MSC_WARNINGS_POP_() +#endif + #ifndef GTEST_LANG_CXX11 // gcc and clang define __GXX_EXPERIMENTAL_CXX0X__ when // -std={c,gnu}++{0x,11} is passed. The C++11 standard specifies a // value for __cplusplus, and recent versions of clang, gcc, and // probably other compilers set that too in C++11 mode. -# if __GXX_EXPERIMENTAL_CXX0X__ || __cplusplus >= 201103L +# if __GXX_EXPERIMENTAL_CXX0X__ || __cplusplus >= 201103L || _MSC_VER >= 1900 // Compiling in at least C++11 mode. # define GTEST_LANG_CXX11 1 # else @@ -355,12 +380,16 @@ #if GTEST_STDLIB_CXX11 # define GTEST_HAS_STD_BEGIN_AND_END_ 1 # define GTEST_HAS_STD_FORWARD_LIST_ 1 -# define GTEST_HAS_STD_FUNCTION_ 1 +# if !defined(_MSC_VER) || (_MSC_FULL_VER >= 190023824) +// works only with VS2015U2 and better +# define GTEST_HAS_STD_FUNCTION_ 1 +# endif # define GTEST_HAS_STD_INITIALIZER_LIST_ 1 # define GTEST_HAS_STD_MOVE_ 1 -# define GTEST_HAS_STD_SHARED_PTR_ 1 -# define GTEST_HAS_STD_TYPE_TRAITS_ 1 # define GTEST_HAS_STD_UNIQUE_PTR_ 1 +# define GTEST_HAS_STD_SHARED_PTR_ 1 +# define GTEST_HAS_UNORDERED_MAP_ 1 +# define GTEST_HAS_UNORDERED_SET_ 1 #endif // C++11 specifies that <tuple> provides std::tuple. @@ -368,7 +397,8 @@ #if GTEST_LANG_CXX11 # define GTEST_HAS_STD_TUPLE_ 1 # if defined(__clang__) -// Inspired by http://clang.llvm.org/docs/LanguageExtensions.html#__has_include +// Inspired by +// https://clang.llvm.org/docs/LanguageExtensions.html#include-file-checking-macros # if defined(__has_include) && !__has_include(<tuple>) # undef GTEST_HAS_STD_TUPLE_ # endif @@ -380,7 +410,7 @@ # elif defined(__GLIBCXX__) // Inspired by boost/config/stdlib/libstdcpp3.hpp, // http://gcc.gnu.org/gcc-4.2/changes.html and -// http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt01ch01.html#manual.intro.status.standard.200x +// https://web.archive.org/web/20140227044429/gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt01ch01.html#manual.intro.status.standard.200x # if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2) # undef GTEST_HAS_STD_TUPLE_ # endif @@ -396,10 +426,16 @@ # include <io.h> # endif // In order to avoid having to include <windows.h>, use forward declaration -// assuming CRITICAL_SECTION is a typedef of _RTL_CRITICAL_SECTION. +#if GTEST_OS_WINDOWS_MINGW && !defined(__MINGW64_VERSION_MAJOR) +// MinGW defined _CRITICAL_SECTION and _RTL_CRITICAL_SECTION as two +// separate (equivalent) structs, instead of using typedef +typedef struct _CRITICAL_SECTION GTEST_CRITICAL_SECTION; +#else +// Assume CRITICAL_SECTION is a typedef of _RTL_CRITICAL_SECTION. // This assumption is verified by // WindowsTypesTest.CRITICAL_SECTIONIs_RTL_CRITICAL_SECTION. -struct _RTL_CRITICAL_SECTION; +typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; +#endif #else // This assumes that non-Windows OSes provide unistd.h. For OSes where this // is not the case, we need to include headers that provide the functions @@ -453,8 +489,11 @@ struct _RTL_CRITICAL_SECTION; #ifndef GTEST_HAS_EXCEPTIONS // The user didn't tell us whether exceptions are enabled, so we need // to figure it out. -# if defined(_MSC_VER) || defined(__BORLANDC__) -// MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS +# if defined(_MSC_VER) && defined(_CPPUNWIND) +// MSVC defines _CPPUNWIND to 1 iff exceptions are enabled. +# define GTEST_HAS_EXCEPTIONS 1 +# elif defined(__BORLANDC__) +// C++Builder's implementation of the STL uses the _HAS_EXCEPTIONS // macro to enable exceptions, so we'll do the same. // Assumes that exceptions are enabled by default. # ifndef _HAS_EXCEPTIONS @@ -498,21 +537,17 @@ struct _RTL_CRITICAL_SECTION; # define GTEST_HAS_STD_STRING 1 #elif !GTEST_HAS_STD_STRING // The user told us that ::std::string isn't available. -# error "Google Test cannot be used where ::std::string isn't available." +# error "::std::string isn't available." #endif // !defined(GTEST_HAS_STD_STRING) #ifndef GTEST_HAS_GLOBAL_STRING -// The user didn't tell us whether ::string is available, so we need -// to figure it out. - # define GTEST_HAS_GLOBAL_STRING 0 - #endif // GTEST_HAS_GLOBAL_STRING #ifndef GTEST_HAS_STD_WSTRING // The user didn't tell us whether ::std::wstring is available, so we need // to figure it out. -// TODO(wan@google.com): uses autoconf to detect whether ::std::wstring +// FIXME: uses autoconf to detect whether ::std::wstring // is available. // Cygwin 1.7 and below doesn't support ::std::wstring. @@ -600,8 +635,9 @@ struct _RTL_CRITICAL_SECTION; // // To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 // to your compiler flags. -# define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX \ - || GTEST_OS_QNX || GTEST_OS_FREEBSD || GTEST_OS_NACL) +#define GTEST_HAS_PTHREAD \ + (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX || GTEST_OS_QNX || \ + GTEST_OS_FREEBSD || GTEST_OS_NACL || GTEST_OS_NETBSD || GTEST_OS_FUCHSIA) #endif // GTEST_HAS_PTHREAD #if GTEST_HAS_PTHREAD @@ -616,7 +652,7 @@ struct _RTL_CRITICAL_SECTION; // Determines if hash_map/hash_set are available. // Only used for testing against those containers. #if !defined(GTEST_HAS_HASH_MAP_) -# if _MSC_VER +# if defined(_MSC_VER) && (_MSC_VER < 1900) # define GTEST_HAS_HASH_MAP_ 1 // Indicates that hash_map is available. # define GTEST_HAS_HASH_SET_ 1 // Indicates that hash_set is available. # endif // _MSC_VER @@ -629,6 +665,14 @@ struct _RTL_CRITICAL_SECTION; # if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) // STLport, provided with the Android NDK, has neither <tr1/tuple> or <tuple>. # define GTEST_HAS_TR1_TUPLE 0 +# elif defined(_MSC_VER) && (_MSC_VER >= 1910) +// Prevent `warning C4996: 'std::tr1': warning STL4002: +// The non-Standard std::tr1 namespace and TR1-only machinery +// are deprecated and will be REMOVED.` +# define GTEST_HAS_TR1_TUPLE 0 +# elif GTEST_LANG_CXX11 && defined(_LIBCPP_VERSION) +// libc++ doesn't support TR1. +# define GTEST_HAS_TR1_TUPLE 0 # else // The user didn't tell us not to do it, so we assume it's OK. # define GTEST_HAS_TR1_TUPLE 1 @@ -638,6 +682,10 @@ struct _RTL_CRITICAL_SECTION; // Determines whether Google Test's own tr1 tuple implementation // should be used. #ifndef GTEST_USE_OWN_TR1_TUPLE +// We use our own tuple implementation on Symbian. +# if GTEST_OS_SYMBIAN +# define GTEST_USE_OWN_TR1_TUPLE 1 +# else // The user didn't tell us, so we need to figure it out. // We use our own TR1 tuple if we aren't sure the user has an @@ -651,7 +699,8 @@ struct _RTL_CRITICAL_SECTION; // support TR1 tuple. libc++ only provides std::tuple, in C++11 mode, // and it can be used with some compilers that define __GNUC__. # if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000) \ - && !GTEST_OS_QNX && !defined(_LIBCPP_VERSION)) || _MSC_VER >= 1600 + && !GTEST_OS_QNX && !defined(_LIBCPP_VERSION)) \ + || (_MSC_VER >= 1600 && _MSC_VER < 1900) # define GTEST_ENV_HAS_TR1_TUPLE_ 1 # endif @@ -667,12 +716,11 @@ struct _RTL_CRITICAL_SECTION; # else # define GTEST_USE_OWN_TR1_TUPLE 1 # endif - +# endif // GTEST_OS_SYMBIAN #endif // GTEST_USE_OWN_TR1_TUPLE -// To avoid conditional compilation everywhere, we make it -// gtest-port.h's responsibility to #include the header implementing -// tuple. +// To avoid conditional compilation we make it gtest-port.h's responsibility +// to #include the header implementing tuple. #if GTEST_HAS_STD_TUPLE_ # include <tuple> // IWYU pragma: export # define GTEST_TUPLE_NAMESPACE_ ::std @@ -687,22 +735,6 @@ struct _RTL_CRITICAL_SECTION; # if GTEST_USE_OWN_TR1_TUPLE # include "gtest/internal/gtest-tuple.h" // IWYU pragma: export // NOLINT -# elif GTEST_ENV_HAS_STD_TUPLE_ -# include <tuple> -// C++11 puts its tuple into the ::std namespace rather than -// ::std::tr1. gtest expects tuple to live in ::std::tr1, so put it there. -// This causes undefined behavior, but supported compilers react in -// the way we intend. -namespace std { -namespace tr1 { -using ::std::get; -using ::std::make_tuple; -using ::std::tuple; -using ::std::tuple_element; -using ::std::tuple_size; -} -} - # elif GTEST_OS_SYMBIAN // On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to @@ -727,20 +759,22 @@ using ::std::tuple_size; // Until version 4.3.2, gcc has a bug that causes <tr1/functional>, // which is #included by <tr1/tuple>, to not compile when RTTI is // disabled. _TR1_FUNCTIONAL is the header guard for -// <tr1/functional>. Hence the following #define is a hack to prevent +// <tr1/functional>. Hence the following #define is used to prevent // <tr1/functional> from being included. # define _TR1_FUNCTIONAL 1 # include <tr1/tuple> # undef _TR1_FUNCTIONAL // Allows the user to #include - // <tr1/functional> if he chooses to. + // <tr1/functional> if they choose to. # else # include <tr1/tuple> // NOLINT # endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 -# else -// If the compiler is not GCC 4.0+, we assume the user is using a -// spec-conforming TR1 implementation. +// VS 2010 now has tr1 support. +# elif _MSC_VER >= 1600 # include <tuple> // IWYU pragma: export // NOLINT + +# else // GTEST_USE_OWN_TR1_TUPLE +# include <tr1/tuple> // IWYU pragma: export // NOLINT # endif // GTEST_USE_OWN_TR1_TUPLE #endif // GTEST_HAS_TR1_TUPLE @@ -754,8 +788,12 @@ using ::std::tuple_size; # if GTEST_OS_LINUX && !defined(__ia64__) # if GTEST_OS_LINUX_ANDROID -// On Android, clone() is only available on ARM starting with Gingerbread. -# if defined(__arm__) && __ANDROID_API__ >= 9 +// On Android, clone() became available at different API levels for each 32-bit +// architecture. +# if defined(__LP64__) || \ + (defined(__arm__) && __ANDROID_API__ >= 9) || \ + (defined(__mips__) && __ANDROID_API__ >= 12) || \ + (defined(__i386__) && __ANDROID_API__ >= 17) # define GTEST_HAS_CLONE 1 # else # define GTEST_HAS_CLONE 0 @@ -786,19 +824,15 @@ using ::std::tuple_size; // Google Test does not support death tests for VC 7.1 and earlier as // abort() in a VC 7.1 application compiled as GUI in debug config // pops up a dialog window that cannot be suppressed programmatically. -#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ - (GTEST_OS_MAC && !GTEST_OS_IOS) || \ - (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ +#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ + (GTEST_OS_MAC && !GTEST_OS_IOS) || \ + (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \ - GTEST_OS_OPENBSD || GTEST_OS_QNX || GTEST_OS_FREEBSD) + GTEST_OS_OPENBSD || GTEST_OS_QNX || GTEST_OS_FREEBSD || \ + GTEST_OS_NETBSD || GTEST_OS_FUCHSIA) # define GTEST_HAS_DEATH_TEST 1 #endif -// We don't support MSVC 7.1 with exceptions disabled now. Therefore -// all the compilers we care about are adequate for supporting -// value-parameterized tests. -#define GTEST_HAS_PARAM_TEST 1 - // Determines whether to support type-driven tests. // Typed tests need <typeinfo> and variadic macros, which GCC, VC++ 8.0, @@ -813,7 +847,7 @@ using ::std::tuple_size; // value-parameterized tests are enabled. The implementation doesn't // work on Sun Studio since it doesn't understand templated conversion // operators. -#if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC) +#if (GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_) && !defined(__SUNPRO_CC) # define GTEST_HAS_COMBINE 1 #endif @@ -864,15 +898,39 @@ using ::std::tuple_size; # define GTEST_ATTRIBUTE_UNUSED_ #endif +#if GTEST_LANG_CXX11 +# define GTEST_CXX11_EQUALS_DELETE_ = delete +#else // GTEST_LANG_CXX11 +# define GTEST_CXX11_EQUALS_DELETE_ +#endif // GTEST_LANG_CXX11 + +// Use this annotation before a function that takes a printf format string. +#if (defined(__GNUC__) || defined(__clang__)) && !defined(COMPILER_ICC) +# if defined(__MINGW_PRINTF_FORMAT) +// MinGW has two different printf implementations. Ensure the format macro +// matches the selected implementation. See +// https://sourceforge.net/p/mingw-w64/wiki2/gnu%20printf/. +# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \ + __attribute__((__format__(__MINGW_PRINTF_FORMAT, string_index, \ + first_to_check))) +# else +# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \ + __attribute__((__format__(__printf__, string_index, first_to_check))) +# endif +#else +# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) +#endif + + // A macro to disallow operator= // This should be used in the private: declarations for a class. -#define GTEST_DISALLOW_ASSIGN_(type)\ - void operator=(type const &) +#define GTEST_DISALLOW_ASSIGN_(type) \ + void operator=(type const &) GTEST_CXX11_EQUALS_DELETE_ // A macro to disallow copy constructor and operator= // This should be used in the private: declarations for a class. -#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\ - type(type const &);\ +#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type) \ + type(type const &) GTEST_CXX11_EQUALS_DELETE_; \ GTEST_DISALLOW_ASSIGN_(type) // Tell the compiler to warn about unused return values for functions declared @@ -920,6 +978,11 @@ using ::std::tuple_size; #endif // GTEST_HAS_SEH +// GTEST_API_ qualifies all symbols that must be exported. The definitions below +// are guarded by #ifndef to give embedders a chance to define GTEST_API_ in +// gtest/internal/custom/gtest-port.h +#ifndef GTEST_API_ + #ifdef _MSC_VER # if GTEST_LINKED_AS_SHARED_LIBRARY # define GTEST_API_ __declspec(dllimport) @@ -928,11 +991,17 @@ using ::std::tuple_size; # endif #elif __GNUC__ >= 4 || defined(__clang__) # define GTEST_API_ __attribute__((visibility ("default"))) -#endif // _MSC_VER +#endif // _MSC_VER + +#endif // GTEST_API_ #ifndef GTEST_API_ # define GTEST_API_ -#endif +#endif // GTEST_API_ + +#ifndef GTEST_DEFAULT_DEATH_TEST_STYLE +# define GTEST_DEFAULT_DEATH_TEST_STYLE "fast" +#endif // GTEST_DEFAULT_DEATH_TEST_STYLE #ifdef __GNUC__ // Ask the compiler to never inline a given function. @@ -942,10 +1011,12 @@ using ::std::tuple_size; #endif // _LIBCPP_VERSION is defined by the libc++ library from the LLVM project. -#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) -# define GTEST_HAS_CXXABI_H_ 1 -#else -# define GTEST_HAS_CXXABI_H_ 0 +#if !defined(GTEST_HAS_CXXABI_H_) +# if defined(__GLIBCXX__) || (defined(_LIBCPP_VERSION) && !defined(_MSC_VER)) +# define GTEST_HAS_CXXABI_H_ 1 +# else +# define GTEST_HAS_CXXABI_H_ 0 +# endif #endif // A function level attribute to disable checking for use of uninitialized @@ -1088,6 +1159,16 @@ struct StaticAssertTypeEqHelper<T, T> { enum { value = true }; }; +// Same as std::is_same<>. +template <typename T, typename U> +struct IsSame { + enum { value = false }; +}; +template <typename T> +struct IsSame<T, T> { + enum { value = true }; +}; + // Evaluates to the number of elements in 'array'. #define GTEST_ARRAY_SIZE_(array) (sizeof(array) / sizeof(array[0])) @@ -1151,6 +1232,10 @@ class scoped_ptr { // Defines RE. +#if GTEST_USES_PCRE +// if used, PCRE is injected by custom/gtest-port.h +#elif GTEST_USES_POSIX_RE || GTEST_USES_SIMPLE_RE + // A simple C++ wrapper for <regex.h>. It uses the POSIX Extended // Regular Expression syntax. class GTEST_API_ RE { @@ -1162,11 +1247,11 @@ class GTEST_API_ RE { // Constructs an RE from a string. RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT -#if GTEST_HAS_GLOBAL_STRING +# if GTEST_HAS_GLOBAL_STRING RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT -#endif // GTEST_HAS_GLOBAL_STRING +# endif // GTEST_HAS_GLOBAL_STRING RE(const char* regex) { Init(regex); } // NOLINT ~RE(); @@ -1179,7 +1264,7 @@ class GTEST_API_ RE { // PartialMatch(str, re) returns true iff regular expression re // matches a substring of str (including str itself). // - // TODO(wan@google.com): make FullMatch() and PartialMatch() work + // FIXME: make FullMatch() and PartialMatch() work // when str contains NUL characters. static bool FullMatch(const ::std::string& str, const RE& re) { return FullMatch(str.c_str(), re); @@ -1188,7 +1273,7 @@ class GTEST_API_ RE { return PartialMatch(str.c_str(), re); } -#if GTEST_HAS_GLOBAL_STRING +# if GTEST_HAS_GLOBAL_STRING static bool FullMatch(const ::string& str, const RE& re) { return FullMatch(str.c_str(), re); @@ -1197,7 +1282,7 @@ class GTEST_API_ RE { return PartialMatch(str.c_str(), re); } -#endif // GTEST_HAS_GLOBAL_STRING +# endif // GTEST_HAS_GLOBAL_STRING static bool FullMatch(const char* str, const RE& re); static bool PartialMatch(const char* str, const RE& re); @@ -1206,25 +1291,27 @@ class GTEST_API_ RE { void Init(const char* regex); // We use a const char* instead of an std::string, as Google Test used to be - // used where std::string is not available. TODO(wan@google.com): change to + // used where std::string is not available. FIXME: change to // std::string. const char* pattern_; bool is_valid_; -#if GTEST_USES_POSIX_RE +# if GTEST_USES_POSIX_RE regex_t full_regex_; // For FullMatch(). regex_t partial_regex_; // For PartialMatch(). -#else // GTEST_USES_SIMPLE_RE +# else // GTEST_USES_SIMPLE_RE const char* full_pattern_; // For FullMatch(); -#endif +# endif GTEST_DISALLOW_ASSIGN_(RE); }; +#endif // GTEST_USES_PCRE + // Formats a source file path and a line number as they would appear // in an error message from the compiler used to compile this code. GTEST_API_ ::std::string FormatFileLocation(const char* file, int line); @@ -1310,13 +1397,59 @@ inline void FlushInfoLog() { fflush(NULL); } GTEST_LOG_(FATAL) << #posix_call << "failed with error " \ << gtest_error +// Adds reference to a type if it is not a reference type, +// otherwise leaves it unchanged. This is the same as +// tr1::add_reference, which is not widely available yet. +template <typename T> +struct AddReference { typedef T& type; }; // NOLINT +template <typename T> +struct AddReference<T&> { typedef T& type; }; // NOLINT + +// A handy wrapper around AddReference that works when the argument T +// depends on template parameters. +#define GTEST_ADD_REFERENCE_(T) \ + typename ::testing::internal::AddReference<T>::type + +// Transforms "T" into "const T&" according to standard reference collapsing +// rules (this is only needed as a backport for C++98 compilers that do not +// support reference collapsing). Specifically, it transforms: +// +// char ==> const char& +// const char ==> const char& +// char& ==> char& +// const char& ==> const char& +// +// Note that the non-const reference will not have "const" added. This is +// standard, and necessary so that "T" can always bind to "const T&". +template <typename T> +struct ConstRef { typedef const T& type; }; +template <typename T> +struct ConstRef<T&> { typedef T& type; }; + +// The argument T must depend on some template parameters. +#define GTEST_REFERENCE_TO_CONST_(T) \ + typename ::testing::internal::ConstRef<T>::type + #if GTEST_HAS_STD_MOVE_ +using std::forward; using std::move; + +template <typename T> +struct RvalueRef { + typedef T&& type; +}; #else // GTEST_HAS_STD_MOVE_ template <typename T> const T& move(const T& t) { return t; } +template <typename T> +GTEST_ADD_REFERENCE_(T) forward(GTEST_ADD_REFERENCE_(T) t) { return t; } + +template <typename T> +struct RvalueRef { + typedef const T& type; +}; #endif // GTEST_HAS_STD_MOVE_ // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. @@ -1417,10 +1550,6 @@ GTEST_API_ void CaptureStderr(); GTEST_API_ std::string GetCapturedStderr(); #endif // GTEST_HAS_STREAM_REDIRECTION - -// Returns a path to temporary directory. -GTEST_API_ std::string TempDir(); - // Returns the size (in bytes) of a file. GTEST_API_ size_t GetFileSize(FILE* file); @@ -1428,14 +1557,18 @@ GTEST_API_ size_t GetFileSize(FILE* file); GTEST_API_ std::string ReadEntireFile(FILE* file); // All command line arguments. -GTEST_API_ const ::std::vector<testing::internal::string>& GetArgvs(); +GTEST_API_ std::vector<std::string> GetArgvs(); #if GTEST_HAS_DEATH_TEST -const ::std::vector<testing::internal::string>& GetInjectableArgvs(); -void SetInjectableArgvs(const ::std::vector<testing::internal::string>* - new_argvs); - +std::vector<std::string> GetInjectableArgvs(); +// Deprecated: pass the args vector by value instead. +void SetInjectableArgvs(const std::vector<std::string>* new_argvs); +void SetInjectableArgvs(const std::vector<std::string>& new_argvs); +#if GTEST_HAS_GLOBAL_STRING +void SetInjectableArgvs(const std::vector< ::string>& new_argvs); +#endif // GTEST_HAS_GLOBAL_STRING +void ClearInjectableArgvs(); #endif // GTEST_HAS_DEATH_TEST @@ -1685,7 +1818,7 @@ class GTEST_API_ Mutex { // Initializes owner_thread_id_ and critical_section_ in static mutexes. void ThreadSafeLazyInit(); - // Per http://blogs.msdn.com/b/oldnewthing/archive/2004/02/23/78395.aspx, + // Per https://blogs.msdn.microsoft.com/oldnewthing/20040223-00/?p=40503, // we assume that 0 is an invalid value for thread IDs. unsigned int owner_thread_id_; @@ -1693,7 +1826,7 @@ class GTEST_API_ Mutex { // by the linker. MutexType type_; long critical_section_init_phase_; // NOLINT - _RTL_CRITICAL_SECTION* critical_section_; + GTEST_CRITICAL_SECTION* critical_section_; GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); }; @@ -1969,8 +2102,13 @@ class MutexBase { extern ::testing::internal::MutexBase mutex // Defines and statically (i.e. at link time) initializes a static mutex. -# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ - ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false, pthread_t() } +// The initialization list here does not explicitly initialize each field, +// instead relying on default initialization for the unspecified fields. In +// particular, the owner_ field (a pthread_t) is not explicitly initialized. +// This allows initialization to work whether pthread_t is a scalar or struct. +// The flag -Wmissing-field-initializers must not be specified for this to work. +#define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ + ::testing::internal::MutexBase mutex = {PTHREAD_MUTEX_INITIALIZER, false, 0} // The Mutex class can only be used for mutexes created at runtime. It // shares its API with MutexBase otherwise. @@ -2027,7 +2165,7 @@ extern "C" inline void DeleteThreadLocalValue(void* value_holder) { // Implements thread-local storage on pthreads-based systems. template <typename T> -class ThreadLocal { +class GTEST_API_ ThreadLocal { public: ThreadLocal() : key_(CreateKey()), default_factory_(new DefaultValueHolderFactory()) {} @@ -2159,7 +2297,7 @@ class GTestMutexLock { typedef GTestMutexLock MutexLock; template <typename T> -class ThreadLocal { +class GTEST_API_ ThreadLocal { public: ThreadLocal() : value_() {} explicit ThreadLocal(const T& value) : value_(value) {} @@ -2178,12 +2316,13 @@ class ThreadLocal { GTEST_API_ size_t GetThreadCount(); // Passing non-POD classes through ellipsis (...) crashes the ARM -// compiler and generates a warning in Sun Studio. The Nokia Symbian +// compiler and generates a warning in Sun Studio before 12u4. The Nokia Symbian // and the IBM XL C/C++ compiler try to instantiate a copy constructor // for objects passed through ellipsis (...), failing for uncopyable // objects. We define this to ensure that only POD is passed through // ellipsis on these systems. -#if defined(__SYMBIAN32__) || defined(__IBMCPP__) || defined(__SUNPRO_CC) +#if defined(__SYMBIAN32__) || defined(__IBMCPP__) || \ + (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x5130) // We lose support for NULL detection where the compiler doesn't like // passing non-POD classes through ellipsis (...). # define GTEST_ELLIPSIS_NEEDS_POD_ 1 @@ -2209,6 +2348,13 @@ template <bool bool_value> const bool bool_constant<bool_value>::value; typedef bool_constant<false> false_type; typedef bool_constant<true> true_type; +template <typename T, typename U> +struct is_same : public false_type {}; + +template <typename T> +struct is_same<T, T> : public true_type {}; + + template <typename T> struct is_pointer : public false_type {}; @@ -2220,6 +2366,7 @@ struct IteratorTraits { typedef typename Iterator::value_type value_type; }; + template <typename T> struct IteratorTraits<T*> { typedef T value_type; @@ -2351,7 +2498,7 @@ inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } // Functions deprecated by MSVC 8.0. -GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996 /* deprecated function */) +GTEST_DISABLE_MSC_DEPRECATED_PUSH_() inline const char* StrNCpy(char* dest, const char* src, size_t n) { return strncpy(dest, src, n); @@ -2385,7 +2532,7 @@ inline int Close(int fd) { return close(fd); } inline const char* StrError(int errnum) { return strerror(errnum); } #endif inline const char* GetEnv(const char* name) { -#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE | GTEST_OS_WINDOWS_RT +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT // We are on Windows CE, which has no environment variables. static_cast<void>(name); // To prevent 'unused argument' warning. return NULL; @@ -2399,7 +2546,7 @@ inline const char* GetEnv(const char* name) { #endif } -GTEST_DISABLE_MSC_WARNINGS_POP_() +GTEST_DISABLE_MSC_DEPRECATED_POP_() #if GTEST_OS_WINDOWS_MOBILE // Windows CE has no C library. The abort() function is used in @@ -2515,15 +2662,15 @@ typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. # define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) # define GTEST_DECLARE_int32_(name) \ GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name) -#define GTEST_DECLARE_string_(name) \ +# define GTEST_DECLARE_string_(name) \ GTEST_API_ extern ::std::string GTEST_FLAG(name) // Macros for defining flags. -#define GTEST_DEFINE_bool_(name, default_val, doc) \ +# define GTEST_DEFINE_bool_(name, default_val, doc) \ GTEST_API_ bool GTEST_FLAG(name) = (default_val) -#define GTEST_DEFINE_int32_(name, default_val, doc) \ +# define GTEST_DEFINE_int32_(name, default_val, doc) \ GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val) -#define GTEST_DEFINE_string_(name, default_val, doc) \ +# define GTEST_DEFINE_string_(name, default_val, doc) \ GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val) #endif // !defined(GTEST_DECLARE_bool_) @@ -2537,7 +2684,7 @@ typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. // Parses 'str' for a 32-bit signed integer. If successful, writes the result // to *value and returns true; otherwise leaves *value unchanged and returns // false. -// TODO(chandlerc): Find a better way to refactor flag and environment parsing +// FIXME: Find a better way to refactor flag and environment parsing // out of both gtest-port.cc and gtest.cc to avoid exporting this utility // function. bool ParseInt32(const Message& src_text, const char* str, Int32* value); @@ -2546,7 +2693,8 @@ bool ParseInt32(const Message& src_text, const char* str, Int32* value); // corresponding to the given Google Test flag. bool BoolFromGTestEnv(const char* flag, bool default_val); GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val); -std::string StringFromGTestEnv(const char* flag, const char* default_val); +std::string OutputFlagAlsoCheckEnvVar(); +const char* StringFromGTestEnv(const char* flag, const char* default_val); } // namespace internal } // namespace testing diff --git a/test/googletest/include/gtest/internal/gtest-string.h b/test/googletest/include/gtest/internal/gtest-string.h index 97f1a7fd..4c9b6262 100644 --- a/test/googletest/include/gtest/internal/gtest-string.h +++ b/test/googletest/include/gtest/internal/gtest-string.h @@ -27,17 +27,17 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file declares the String class and functions used internally by // Google Test. They are subject to change without notice. They should not used // by code external to Google Test. // -// This header file is #included by <gtest/internal/gtest-internal.h>. +// This header file is #included by gtest-internal.h. // It should not be #included by other files. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ diff --git a/test/googletest/include/gtest/internal/gtest-tuple.h b/test/googletest/include/gtest/internal/gtest-tuple.h index e9b40534..78a3a6a0 100644 --- a/test/googletest/include/gtest/internal/gtest-tuple.h +++ b/test/googletest/include/gtest/internal/gtest-tuple.h @@ -30,11 +30,12 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) + // Implements a subset of TR1 tuple needed by Google Test and Google Mock. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ @@ -42,7 +43,7 @@ // The compiler used in Symbian has a bug that prevents us from declaring the // tuple template as a friend (it complains that tuple is redefined). This -// hack bypasses the bug by declaring the members that should otherwise be +// bypasses the bug by declaring the members that should otherwise be // private as public. // Sun Studio versions < 12 also have the above bug. #if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) diff --git a/test/googletest/include/gtest/internal/gtest-tuple.h.pump b/test/googletest/include/gtest/internal/gtest-tuple.h.pump index 429ddfee..bb626e04 100644 --- a/test/googletest/include/gtest/internal/gtest-tuple.h.pump +++ b/test/googletest/include/gtest/internal/gtest-tuple.h.pump @@ -29,11 +29,12 @@ $$ This meta comment fixes auto-indentation in Emacs. }} // 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. -// -// Author: wan@google.com (Zhanyong Wan) + // Implements a subset of TR1 tuple needed by Google Test and Google Mock. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ @@ -41,7 +42,7 @@ $$ This meta comment fixes auto-indentation in Emacs. }} // The compiler used in Symbian has a bug that prevents us from declaring the // tuple template as a friend (it complains that tuple is redefined). This -// hack bypasses the bug by declaring the members that should otherwise be +// bypasses the bug by declaring the members that should otherwise be // private as public. // Sun Studio versions < 12 also have the above bug. #if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) diff --git a/test/googletest/include/gtest/internal/gtest-type-util.h b/test/googletest/include/gtest/internal/gtest-type-util.h index e46f7cfc..28e41124 100644 --- a/test/googletest/include/gtest/internal/gtest-type-util.h +++ b/test/googletest/include/gtest/internal/gtest-type-util.h @@ -30,8 +30,7 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) + // Type utilities needed for implementing typed and type-parameterized // tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! @@ -41,6 +40,8 @@ // Please contact googletestframework@googlegroups.com if you need // more. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ @@ -57,6 +58,22 @@ namespace testing { namespace internal { +// Canonicalizes a given name with respect to the Standard C++ Library. +// This handles removing the inline namespace within `std` that is +// used by various standard libraries (e.g., `std::__1`). Names outside +// of namespace std are returned unmodified. +inline std::string CanonicalizeForStdLibVersioning(std::string s) { + static const char prefix[] = "std::__"; + if (s.compare(0, strlen(prefix), prefix) == 0) { + std::string::size_type end = s.find("::", strlen(prefix)); + if (end != s.npos) { + // Erase everything between the initial `std` and the second `::`. + s.erase(strlen("std"), end - strlen("std")); + } + } + return s; +} + // GetTypeName<T>() returns a human-readable name of type T. // NB: This function is also used in Google Mock, so don't move it inside of // the typed-test-only section below. @@ -75,7 +92,7 @@ std::string GetTypeName() { char* const readable_name = __cxa_demangle(name, 0, 0, &status); const std::string name_str(status == 0 ? readable_name : name); free(readable_name); - return name_str; + return CanonicalizeForStdLibVersioning(name_str); # else return name; # endif // GTEST_HAS_CXXABI_H_ || __HP_aCC diff --git a/test/googletest/include/gtest/internal/gtest-type-util.h.pump b/test/googletest/include/gtest/internal/gtest-type-util.h.pump index 251fdf02..0001a5d3 100644 --- a/test/googletest/include/gtest/internal/gtest-type-util.h.pump +++ b/test/googletest/include/gtest/internal/gtest-type-util.h.pump @@ -28,8 +28,7 @@ $var n = 50 $$ Maximum length of type lists we want to support. // 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. -// -// Author: wan@google.com (Zhanyong Wan) + // Type utilities needed for implementing typed and type-parameterized // tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! @@ -39,6 +38,8 @@ $var n = 50 $$ Maximum length of type lists we want to support. // Please contact googletestframework@googlegroups.com if you need // more. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ @@ -55,6 +56,22 @@ $var n = 50 $$ Maximum length of type lists we want to support. namespace testing { namespace internal { +// Canonicalizes a given name with respect to the Standard C++ Library. +// This handles removing the inline namespace within `std` that is +// used by various standard libraries (e.g., `std::__1`). Names outside +// of namespace std are returned unmodified. +inline std::string CanonicalizeForStdLibVersioning(std::string s) { + static const char prefix[] = "std::__"; + if (s.compare(0, strlen(prefix), prefix) == 0) { + std::string::size_type end = s.find("::", strlen(prefix)); + if (end != s.npos) { + // Erase everything between the initial `std` and the second `::`. + s.erase(strlen("std"), end - strlen("std")); + } + } + return s; +} + // GetTypeName<T>() returns a human-readable name of type T. // NB: This function is also used in Google Mock, so don't move it inside of // the typed-test-only section below. @@ -73,7 +90,7 @@ std::string GetTypeName() { char* const readable_name = __cxa_demangle(name, 0, 0, &status); const std::string name_str(status == 0 ? readable_name : name); free(readable_name); - return name_str; + return CanonicalizeForStdLibVersioning(name_str); # else return name; # endif // GTEST_HAS_CXXABI_H_ || __HP_aCC diff --git a/test/googletest/src/gtest-all.cc b/test/googletest/src/gtest-all.cc index 0a9cee52..b217a180 100644 --- a/test/googletest/src/gtest-all.cc +++ b/test/googletest/src/gtest-all.cc @@ -26,10 +26,9 @@ // 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. + // -// Author: mheule@google.com (Markus Heule) -// -// Google C++ Testing Framework (Google Test) +// Google C++ Testing and Mocking Framework (Google Test) // // Sometimes it's desirable to build Google Test by compiling a single file. // This file serves this purpose. diff --git a/test/googletest/src/gtest-death-test.cc b/test/googletest/src/gtest-death-test.cc index a01a3698..09083551 100644 --- a/test/googletest/src/gtest-death-test.cc +++ b/test/googletest/src/gtest-death-test.cc @@ -26,8 +26,7 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev) + // // This file implements death tests. @@ -62,26 +61,30 @@ # include <spawn.h> # endif // GTEST_OS_QNX +# if GTEST_OS_FUCHSIA +# include <lib/fdio/io.h> +# include <lib/fdio/spawn.h> +# include <zircon/processargs.h> +# include <zircon/syscalls.h> +# include <zircon/syscalls/port.h> +# endif // GTEST_OS_FUCHSIA + #endif // GTEST_HAS_DEATH_TEST #include "gtest/gtest-message.h" #include "gtest/internal/gtest-string.h" - -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick exists to -// prevent the accidental inclusion of gtest-internal-inl.h in the -// user's code. -#define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" -#undef GTEST_IMPLEMENTATION_ namespace testing { // Constants. // The default death test style. -static const char kDefaultDeathTestStyle[] = "fast"; +// +// This is defined in internal/gtest-port.h as "fast", but can be overridden by +// a definition in internal/custom/gtest-port.h. The recommended value, which is +// used internally at Google, is "threadsafe". +static const char kDefaultDeathTestStyle[] = GTEST_DEFAULT_DEATH_TEST_STYLE; GTEST_DEFINE_string_( death_test_style, @@ -121,7 +124,7 @@ namespace internal { // Valid only for fast death tests. Indicates the code is running in the // child process of a fast style death test. -# if !GTEST_OS_WINDOWS +# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA static bool g_in_fast_death_test_child = false; # endif @@ -131,10 +134,10 @@ static bool g_in_fast_death_test_child = false; // tests. IMPORTANT: This is an internal utility. Using it may break the // implementation of death tests. User code MUST NOT use it. bool InDeathTestChild() { -# if GTEST_OS_WINDOWS +# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA - // On Windows, death tests are thread-safe regardless of the value of the - // death_test_style flag. + // On Windows and Fuchsia, death tests are thread-safe regardless of the value + // of the death_test_style flag. return !GTEST_FLAG(internal_run_death_test).empty(); # else @@ -154,7 +157,7 @@ ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { // ExitedWithCode function-call operator. bool ExitedWithCode::operator()(int exit_status) const { -# if GTEST_OS_WINDOWS +# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA return exit_status == exit_code_; @@ -162,10 +165,10 @@ bool ExitedWithCode::operator()(int exit_status) const { return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; -# endif // GTEST_OS_WINDOWS +# endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA } -# if !GTEST_OS_WINDOWS +# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // KilledBySignal constructor. KilledBySignal::KilledBySignal(int signum) : signum_(signum) { } @@ -182,7 +185,7 @@ bool KilledBySignal::operator()(int exit_status) const { # endif // defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_) return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; } -# endif // !GTEST_OS_WINDOWS +# endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA namespace internal { @@ -193,7 +196,7 @@ namespace internal { static std::string ExitSummary(int exit_code) { Message m; -# if GTEST_OS_WINDOWS +# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA m << "Exited with exit status " << exit_code; @@ -209,7 +212,7 @@ static std::string ExitSummary(int exit_code) { m << " (core dumped)"; } # endif -# endif // GTEST_OS_WINDOWS +# endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA return m.GetString(); } @@ -220,7 +223,7 @@ bool ExitedUnsuccessfully(int exit_status) { return !ExitedWithCode(0)(exit_status); } -# if !GTEST_OS_WINDOWS +# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // Generates a textual failure message when a death test finds more than // one thread running, or cannot determine the number of threads, prior // to executing the given statement. It is the responsibility of the @@ -229,13 +232,19 @@ static std::string DeathTestThreadWarning(size_t thread_count) { Message msg; msg << "Death tests use fork(), which is unsafe particularly" << " in a threaded context. For this test, " << GTEST_NAME_ << " "; - if (thread_count == 0) + if (thread_count == 0) { msg << "couldn't detect the number of threads."; - else + } else { msg << "detected " << thread_count << " threads."; + } + msg << " See " + "https://github.com/google/googletest/blob/master/googletest/docs/" + "advanced.md#death-tests-and-threads" + << " for more explanation and suggested solutions, especially if" + << " this is the last message you see before your test times out."; return msg.GetString(); } -# endif // !GTEST_OS_WINDOWS +# endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // Flag characters for reporting a death test that did not die. static const char kDeathTestLived = 'L'; @@ -243,6 +252,13 @@ static const char kDeathTestReturned = 'R'; static const char kDeathTestThrew = 'T'; static const char kDeathTestInternalError = 'I'; +#if GTEST_OS_FUCHSIA + +// File descriptor used for the pipe in the child process. +static const int kFuchsiaReadPipeFd = 3; + +#endif + // An enumeration describing all of the possible ways that a death test can // conclude. DIED means that the process died while executing the test // code; LIVED means that process lived beyond the end of the test code; @@ -250,7 +266,7 @@ static const char kDeathTestInternalError = 'I'; // statement, which is not allowed; THREW means that the test statement // returned control by throwing an exception. IN_PROGRESS means the test // has not yet concluded. -// TODO(vladl@google.com): Unify names and possibly values for +// FIXME: Unify names and possibly values for // AbortReason, DeathTestOutcome, and flag characters above. enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; @@ -259,7 +275,7 @@ enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; // message is propagated back to the parent process. Otherwise, the // message is simply printed to stderr. In either case, the program // then exits with status 1. -void DeathTestAbort(const std::string& message) { +static void DeathTestAbort(const std::string& message) { // On a POSIX system, this function may be called from a threadsafe-style // death test child process, which operates on a very small stack. Use // the heap for any additional non-minuscule memory requirements. @@ -563,7 +579,12 @@ bool DeathTestImpl::Passed(bool status_ok) { break; case DIED: if (status_ok) { +# if GTEST_USES_PCRE + // PCRE regexes support embedded NULs. + const bool matched = RE::PartialMatch(error_message, *regex()); +# else const bool matched = RE::PartialMatch(error_message.c_str(), *regex()); +# endif // GTEST_USES_PCRE if (matched) { success = true; } else { @@ -779,7 +800,200 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { set_spawned(true); return OVERSEE_TEST; } -# else // We are not on Windows. + +# elif GTEST_OS_FUCHSIA + +class FuchsiaDeathTest : public DeathTestImpl { + public: + FuchsiaDeathTest(const char* a_statement, + const RE* a_regex, + const char* file, + int line) + : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {} + virtual ~FuchsiaDeathTest() { + zx_status_t status = zx_handle_close(child_process_); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + status = zx_handle_close(port_); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + } + + // All of these virtual functions are inherited from DeathTest. + virtual int Wait(); + virtual TestRole AssumeRole(); + + private: + // The name of the file in which the death test is located. + const char* const file_; + // The line number on which the death test is located. + const int line_; + + zx_handle_t child_process_ = ZX_HANDLE_INVALID; + zx_handle_t port_ = ZX_HANDLE_INVALID; +}; + +// Utility class for accumulating command-line arguments. +class Arguments { + public: + Arguments() { + args_.push_back(NULL); + } + + ~Arguments() { + for (std::vector<char*>::iterator i = args_.begin(); i != args_.end(); + ++i) { + free(*i); + } + } + void AddArgument(const char* argument) { + args_.insert(args_.end() - 1, posix::StrDup(argument)); + } + + template <typename Str> + void AddArguments(const ::std::vector<Str>& arguments) { + for (typename ::std::vector<Str>::const_iterator i = arguments.begin(); + i != arguments.end(); + ++i) { + args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); + } + } + char* const* Argv() { + return &args_[0]; + } + + int size() { + return args_.size() - 1; + } + + private: + std::vector<char*> args_; +}; + +// Waits for the child in a death test to exit, returning its exit +// status, or 0 if no child process exists. As a side effect, sets the +// outcome data member. +int FuchsiaDeathTest::Wait() { + if (!spawned()) + return 0; + + // Register to wait for the child process to terminate. + zx_status_t status_zx; + status_zx = zx_object_wait_async(child_process_, + port_, + 0 /* key */, + ZX_PROCESS_TERMINATED, + ZX_WAIT_ASYNC_ONCE); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + // Wait for it to terminate, or an exception to be received. + zx_port_packet_t packet; + status_zx = zx_port_wait(port_, ZX_TIME_INFINITE, &packet); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + if (ZX_PKT_IS_EXCEPTION(packet.type)) { + // Process encountered an exception. Kill it directly rather than letting + // other handlers process the event. + status_zx = zx_task_kill(child_process_); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + // Now wait for |child_process_| to terminate. + zx_signals_t signals = 0; + status_zx = zx_object_wait_one( + child_process_, ZX_PROCESS_TERMINATED, ZX_TIME_INFINITE, &signals); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + GTEST_DEATH_TEST_CHECK_(signals & ZX_PROCESS_TERMINATED); + } else { + // Process terminated. + GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type)); + GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_PROCESS_TERMINATED); + } + + ReadAndInterpretStatusByte(); + + zx_info_process_t buffer; + status_zx = zx_object_get_info( + child_process_, + ZX_INFO_PROCESS, + &buffer, + sizeof(buffer), + nullptr, + nullptr); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + GTEST_DEATH_TEST_CHECK_(buffer.exited); + set_status(buffer.return_code); + return status(); +} + +// The AssumeRole process for a Fuchsia death test. It creates a child +// process with the same executable as the current process to run the +// death test. The child process is given the --gtest_filter and +// --gtest_internal_run_death_test flags such that it knows to run the +// current death test only. +DeathTest::TestRole FuchsiaDeathTest::AssumeRole() { + const UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const TestInfo* const info = impl->current_test_info(); + const int death_test_index = info->result()->death_test_count(); + + if (flag != NULL) { + // ParseInternalRunDeathTestFlag() has performed all the necessary + // processing. + set_write_fd(kFuchsiaReadPipeFd); + return EXECUTE_TEST; + } + + CaptureStderr(); + // Flush the log buffers since the log streams are shared with the child. + FlushInfoLog(); + + // Build the child process command line. + const std::string filter_flag = + std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" + + info->test_case_name() + "." + info->name(); + const std::string internal_flag = + std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + + file_ + "|" + + StreamableToString(line_) + "|" + + StreamableToString(death_test_index); + Arguments args; + args.AddArguments(GetInjectableArgvs()); + args.AddArgument(filter_flag.c_str()); + args.AddArgument(internal_flag.c_str()); + + // Build the pipe for communication with the child. + zx_status_t status; + zx_handle_t child_pipe_handle; + uint32_t type; + status = fdio_pipe_half(&child_pipe_handle, &type); + GTEST_DEATH_TEST_CHECK_(status >= 0); + set_read_fd(status); + + // Set the pipe handle for the child. + fdio_spawn_action_t add_handle_action = {}; + add_handle_action.action = FDIO_SPAWN_ACTION_ADD_HANDLE; + add_handle_action.h.id = PA_HND(type, kFuchsiaReadPipeFd); + add_handle_action.h.handle = child_pipe_handle; + + // Spawn the child process. + status = fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, + args.Argv()[0], args.Argv(), nullptr, 1, + &add_handle_action, &child_process_, nullptr); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + + // Create an exception port and attach it to the |child_process_|, to allow + // us to suppress the system default exception handler from firing. + status = zx_port_create(0, &port_); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + status = zx_task_bind_exception_port( + child_process_, port_, 0 /* key */, 0 /*options */); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + + set_spawned(true); + return OVERSEE_TEST; +} + +#else // We are neither on Windows, nor on Fuchsia. // ForkingDeathTest provides implementations for most of the abstract // methods of the DeathTest interface. Only the AssumeRole method is @@ -883,11 +1097,10 @@ class ExecDeathTest : public ForkingDeathTest { ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } virtual TestRole AssumeRole(); private: - static ::std::vector<testing::internal::string> - GetArgvsForDeathTestChildProcess() { - ::std::vector<testing::internal::string> args = GetInjectableArgvs(); + static ::std::vector<std::string> GetArgvsForDeathTestChildProcess() { + ::std::vector<std::string> args = GetInjectableArgvs(); # if defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_) - ::std::vector<testing::internal::string> extra_args = + ::std::vector<std::string> extra_args = GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_(); args.insert(args.end(), extra_args.begin(), extra_args.end()); # endif // defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_) @@ -986,6 +1199,7 @@ static int ExecDeathTestChildMain(void* child_arg) { } # endif // !GTEST_OS_QNX +# if GTEST_HAS_CLONE // Two utility routines that together determine the direction the stack // grows. // This could be accomplished more elegantly by a single recursive @@ -995,20 +1209,22 @@ static int ExecDeathTestChildMain(void* child_arg) { // GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining // StackLowerThanAddress into StackGrowsDown, which then doesn't give // correct answer. -void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_; -void StackLowerThanAddress(const void* ptr, bool* result) { +static void StackLowerThanAddress(const void* ptr, + bool* result) GTEST_NO_INLINE_; +static void StackLowerThanAddress(const void* ptr, bool* result) { int dummy; *result = (&dummy < ptr); } // Make sure AddressSanitizer does not tamper with the stack here. GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ -bool StackGrowsDown() { +static bool StackGrowsDown() { int dummy; bool result; StackLowerThanAddress(&dummy, &result); return result; } +# endif // GTEST_HAS_CLONE // Spawns a child process with the same executable as the current process in // a thread-safe manner and instructs it to run the death test. The @@ -1200,6 +1416,13 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, *test = new WindowsDeathTest(statement, regex, file, line); } +# elif GTEST_OS_FUCHSIA + + if (GTEST_FLAG(death_test_style) == "threadsafe" || + GTEST_FLAG(death_test_style) == "fast") { + *test = new FuchsiaDeathTest(statement, regex, file, line); + } + # else if (GTEST_FLAG(death_test_style) == "threadsafe") { @@ -1224,7 +1447,7 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, // Recreates the pipe and event handles from the provided parameters, // signals the event, and returns a file descriptor wrapped around the pipe // handle. This function is called in the child process only. -int GetStatusFileDescriptor(unsigned int parent_process_id, +static int GetStatusFileDescriptor(unsigned int parent_process_id, size_t write_handle_as_size_t, size_t event_handle_as_size_t) { AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, @@ -1235,7 +1458,7 @@ int GetStatusFileDescriptor(unsigned int parent_process_id, StreamableToString(parent_process_id)); } - // TODO(vladl@google.com): Replace the following check with a + // FIXME: Replace the following check with a // compile-time assertion when available. GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); @@ -1243,7 +1466,7 @@ int GetStatusFileDescriptor(unsigned int parent_process_id, reinterpret_cast<HANDLE>(write_handle_as_size_t); HANDLE dup_write_handle; - // The newly initialized handle is accessible only in in the parent + // The newly initialized handle is accessible only in the parent // process. To obtain one accessible within the child, we need to use // DuplicateHandle. if (!::DuplicateHandle(parent_process_handle.Get(), write_handle, @@ -1320,6 +1543,16 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { write_fd = GetStatusFileDescriptor(parent_process_id, write_handle_as_size_t, event_handle_as_size_t); + +# elif GTEST_OS_FUCHSIA + + if (fields.size() != 3 + || !ParseNaturalNumber(fields[1], &line) + || !ParseNaturalNumber(fields[2], &index)) { + DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + + GTEST_FLAG(internal_run_death_test)); + } + # else if (fields.size() != 4 diff --git a/test/googletest/src/gtest-filepath.cc b/test/googletest/src/gtest-filepath.cc index 0292dc11..a7e65c08 100644 --- a/test/googletest/src/gtest-filepath.cc +++ b/test/googletest/src/gtest-filepath.cc @@ -26,14 +26,12 @@ // 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. -// -// Authors: keith.ray@gmail.com (Keith Ray) -#include "gtest/gtest-message.h" #include "gtest/internal/gtest-filepath.h" -#include "gtest/internal/gtest-port.h" #include <stdlib.h> +#include "gtest/internal/gtest-port.h" +#include "gtest/gtest-message.h" #if GTEST_OS_WINDOWS_MOBILE # include <windows.h> @@ -48,6 +46,8 @@ # include <climits> // Some Linux distributions define PATH_MAX here. #endif // GTEST_OS_WINDOWS_MOBILE +#include "gtest/internal/gtest-string.h" + #if GTEST_OS_WINDOWS # define GTEST_PATH_MAX_ _MAX_PATH #elif defined(PATH_MAX) @@ -58,8 +58,6 @@ # define GTEST_PATH_MAX_ _POSIX_PATH_MAX #endif // GTEST_OS_WINDOWS -#include "gtest/internal/gtest-string.h" - namespace testing { namespace internal { @@ -130,7 +128,7 @@ FilePath FilePath::RemoveExtension(const char* extension) const { return *this; } -// Returns a pointer to the last occurence of a valid path separator in +// Returns a pointer to the last occurrence of a valid path separator in // the FilePath. On Windows, for example, both '/' and '\' are valid path // separators. Returns NULL if no path separator was found. const char* FilePath::FindLastPathSeparator() const { @@ -252,7 +250,7 @@ bool FilePath::DirectoryExists() const { // root directory per disk drive.) bool FilePath::IsRootDirectory() const { #if GTEST_OS_WINDOWS - // TODO(wan@google.com): on Windows a network share like + // FIXME: on Windows a network share like // \\server\share can be a root directory, although it cannot be the // current directory. Handle this properly. return pathname_.length() == 3 && IsAbsolutePath(); @@ -352,7 +350,7 @@ FilePath FilePath::RemoveTrailingPathSeparator() const { // Removes any redundant separators that might be in the pathname. // For example, "bar///foo" becomes "bar/foo". Does not eliminate other // redundancies that might be in a pathname involving "." or "..". -// TODO(wan@google.com): handle Windows network shares (e.g. \\server\share). +// FIXME: handle Windows network shares (e.g. \\server\share). void FilePath::Normalize() { if (pathname_.c_str() == NULL) { pathname_ = ""; diff --git a/test/googletest/src/gtest-internal-inl.h b/test/googletest/src/gtest-internal-inl.h index ed8a682a..47900414 100644 --- a/test/googletest/src/gtest-internal-inl.h +++ b/test/googletest/src/gtest-internal-inl.h @@ -27,24 +27,13 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Utility functions and classes used by the Google C++ testing framework. -// -// Author: wan@google.com (Zhanyong Wan) -// +// Utility functions and classes used by the Google C++ testing framework.// // This file contains purely Google Test's internal implementation. Please // DO NOT #INCLUDE IT IN A USER PROGRAM. #ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_ #define GTEST_SRC_GTEST_INTERNAL_INL_H_ -// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is -// part of Google Test's implementation; otherwise it's undefined. -#if !GTEST_IMPLEMENTATION_ -// If this file is included from the user's code, just say no. -# error "gtest-internal-inl.h is part of Google Test's internal implementation." -# error "It must not be included except by Google Test itself." -#endif // GTEST_IMPLEMENTATION_ - #ifndef _WIN32_WCE # include <errno.h> #endif // !_WIN32_WCE @@ -67,9 +56,12 @@ # include <windows.h> // NOLINT #endif // GTEST_OS_WINDOWS -#include "gtest/gtest.h" // NOLINT +#include "gtest/gtest.h" #include "gtest/gtest-spi.h" +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + namespace testing { // Declares the flags. @@ -94,6 +86,7 @@ const char kFilterFlag[] = "filter"; const char kListTestsFlag[] = "list_tests"; const char kOutputFlag[] = "output"; const char kPrintTimeFlag[] = "print_time"; +const char kPrintUTF8Flag[] = "print_utf8"; const char kRandomSeedFlag[] = "random_seed"; const char kRepeatFlag[] = "repeat"; const char kShuffleFlag[] = "shuffle"; @@ -174,6 +167,7 @@ class GTestFlagSaver { list_tests_ = GTEST_FLAG(list_tests); output_ = GTEST_FLAG(output); print_time_ = GTEST_FLAG(print_time); + print_utf8_ = GTEST_FLAG(print_utf8); random_seed_ = GTEST_FLAG(random_seed); repeat_ = GTEST_FLAG(repeat); shuffle_ = GTEST_FLAG(shuffle); @@ -195,6 +189,7 @@ class GTestFlagSaver { GTEST_FLAG(list_tests) = list_tests_; GTEST_FLAG(output) = output_; GTEST_FLAG(print_time) = print_time_; + GTEST_FLAG(print_utf8) = print_utf8_; GTEST_FLAG(random_seed) = random_seed_; GTEST_FLAG(repeat) = repeat_; GTEST_FLAG(shuffle) = shuffle_; @@ -216,6 +211,7 @@ class GTestFlagSaver { bool list_tests_; std::string output_; bool print_time_; + bool print_utf8_; internal::Int32 random_seed_; internal::Int32 repeat_; bool shuffle_; @@ -426,7 +422,7 @@ class OsStackTraceGetterInterface { // in the trace. // skip_count - the number of top frames to be skipped; doesn't count // against max_depth. - virtual string CurrentStackTrace(int max_depth, int skip_count) = 0; + virtual std::string CurrentStackTrace(int max_depth, int skip_count) = 0; // UponLeavingGTest() should be called immediately before Google Test calls // user code. It saves some information about the current stack that @@ -446,10 +442,20 @@ class OsStackTraceGetter : public OsStackTraceGetterInterface { public: OsStackTraceGetter() {} - virtual string CurrentStackTrace(int max_depth, int skip_count); + virtual std::string CurrentStackTrace(int max_depth, int skip_count); virtual void UponLeavingGTest(); private: +#if GTEST_HAS_ABSL + Mutex mutex_; // Protects all internal state. + + // We save the stack frame below the frame that calls user code. + // We do this because the address of the frame immediately below + // the user code changes between the call to UponLeavingGTest() + // and any calls to the stack trace code from within the user code. + void* caller_frame_ = nullptr; +#endif // GTEST_HAS_ABSL + GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); }; @@ -664,13 +670,11 @@ class GTEST_API_ UnitTestImpl { tear_down_tc)->AddTestInfo(test_info); } -#if GTEST_HAS_PARAM_TEST // Returns ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. internal::ParameterizedTestCaseRegistry& parameterized_test_registry() { return parameterized_test_registry_; } -#endif // GTEST_HAS_PARAM_TEST // Sets the TestCase object for the test that's currently running. void set_current_test_case(TestCase* a_current_test_case) { @@ -845,14 +849,12 @@ class GTEST_API_ UnitTestImpl { // shuffled order. std::vector<int> test_case_indices_; -#if GTEST_HAS_PARAM_TEST // ParameterizedTestRegistry object used to register value-parameterized // tests. internal::ParameterizedTestCaseRegistry parameterized_test_registry_; // Indicates whether RegisterParameterizedTests() has been called already. bool parameterized_tests_registered_; -#endif // GTEST_HAS_PARAM_TEST // Index of the last death test case registered. Initially -1. int last_death_test_case_; @@ -992,7 +994,7 @@ bool ParseNaturalNumber(const ::std::string& str, Integer* number) { const bool parse_success = *end == '\0' && errno == 0; - // TODO(vladl@google.com): Convert this to compile time assertion when it is + // FIXME: Convert this to compile time assertion when it is // available. GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); @@ -1032,7 +1034,7 @@ class TestResultAccessor { #if GTEST_CAN_STREAM_RESULTS_ // Streams test results to the given port on the given host machine. -class GTEST_API_ StreamingListener : public EmptyTestEventListener { +class StreamingListener : public EmptyTestEventListener { public: // Abstract base class for writing strings to a socket. class AbstractSocketWriter { @@ -1040,21 +1042,19 @@ class GTEST_API_ StreamingListener : public EmptyTestEventListener { virtual ~AbstractSocketWriter() {} // Sends a string to the socket. - virtual void Send(const string& message) = 0; + virtual void Send(const std::string& message) = 0; // Closes the socket. virtual void CloseConnection() {} // Sends a string and a newline to the socket. - void SendLn(const string& message) { - Send(message + "\n"); - } + void SendLn(const std::string& message) { Send(message + "\n"); } }; // Concrete class for actually writing strings to a socket. class SocketWriter : public AbstractSocketWriter { public: - SocketWriter(const string& host, const string& port) + SocketWriter(const std::string& host, const std::string& port) : sockfd_(-1), host_name_(host), port_num_(port) { MakeConnection(); } @@ -1065,7 +1065,7 @@ class GTEST_API_ StreamingListener : public EmptyTestEventListener { } // Sends a string to the socket. - virtual void Send(const string& message) { + virtual void Send(const std::string& message) { GTEST_CHECK_(sockfd_ != -1) << "Send() can be called only when there is a connection."; @@ -1091,17 +1091,19 @@ class GTEST_API_ StreamingListener : public EmptyTestEventListener { } int sockfd_; // socket file descriptor - const string host_name_; - const string port_num_; + const std::string host_name_; + const std::string port_num_; GTEST_DISALLOW_COPY_AND_ASSIGN_(SocketWriter); }; // class SocketWriter // Escapes '=', '&', '%', and '\n' characters in str as "%xx". - static string UrlEncode(const char* str); + static std::string UrlEncode(const char* str); - StreamingListener(const string& host, const string& port) - : socket_writer_(new SocketWriter(host, port)) { Start(); } + StreamingListener(const std::string& host, const std::string& port) + : socket_writer_(new SocketWriter(host, port)) { + Start(); + } explicit StreamingListener(AbstractSocketWriter* socket_writer) : socket_writer_(socket_writer) { Start(); } @@ -1162,13 +1164,13 @@ class GTEST_API_ StreamingListener : public EmptyTestEventListener { private: // Sends the given message and a newline to the socket. - void SendLn(const string& message) { socket_writer_->SendLn(message); } + void SendLn(const std::string& message) { socket_writer_->SendLn(message); } // Called at the start of streaming to notify the receiver what // protocol we are using. void Start() { SendLn("gtest_streaming_protocol_version=1.0"); } - string FormatBool(bool value) { return value ? "1" : "0"; } + std::string FormatBool(bool value) { return value ? "1" : "0"; } const scoped_ptr<AbstractSocketWriter> socket_writer_; @@ -1180,4 +1182,6 @@ class GTEST_API_ StreamingListener : public EmptyTestEventListener { } // namespace internal } // namespace testing +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + #endif // GTEST_SRC_GTEST_INTERNAL_INL_H_ diff --git a/test/googletest/src/gtest-port.cc b/test/googletest/src/gtest-port.cc index e5bf3dd2..fecb5d11 100644 --- a/test/googletest/src/gtest-port.cc +++ b/test/googletest/src/gtest-port.cc @@ -26,8 +26,7 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) + #include "gtest/internal/gtest-port.h" @@ -63,19 +62,16 @@ # include <sys/types.h> #endif // GTEST_OS_AIX +#if GTEST_OS_FUCHSIA +# include <zircon/process.h> +# include <zircon/syscalls.h> +#endif // GTEST_OS_FUCHSIA + #include "gtest/gtest-spi.h" #include "gtest/gtest-message.h" #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-string.h" - -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick exists to -// prevent the accidental inclusion of gtest-internal-inl.h in the -// user's code. -#define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" -#undef GTEST_IMPLEMENTATION_ namespace testing { namespace internal { @@ -93,7 +89,7 @@ const int kStdErrFileno = STDERR_FILENO; namespace { template <typename T> -T ReadProcFileField(const string& filename, int field) { +T ReadProcFileField(const std::string& filename, int field) { std::string dummy; std::ifstream file(filename.c_str()); while (field-- > 0) { @@ -107,7 +103,7 @@ T ReadProcFileField(const string& filename, int field) { // Returns the number of active threads, or 0 when there is an error. size_t GetThreadCount() { - const string filename = + const std::string filename = (Message() << "/proc/" << getpid() << "/stat").GetString(); return ReadProcFileField<int>(filename, 19); } @@ -164,6 +160,25 @@ size_t GetThreadCount() { } } +#elif GTEST_OS_FUCHSIA + +size_t GetThreadCount() { + int dummy_buffer; + size_t avail; + zx_status_t status = zx_object_get_info( + zx_process_self(), + ZX_INFO_PROCESS_THREADS, + &dummy_buffer, + 0, + nullptr, + &avail); + if (status == ZX_OK) { + return avail; + } else { + return 0; + } +} + #else size_t GetThreadCount() { @@ -246,9 +261,9 @@ Mutex::Mutex() Mutex::~Mutex() { // Static mutexes are leaked intentionally. It is not thread-safe to try // to clean them up. - // TODO(yukawa): Switch to Slim Reader/Writer (SRW) Locks, which requires + // FIXME: Switch to Slim Reader/Writer (SRW) Locks, which requires // nothing to clean it up but is available only on Vista and later. - // http://msdn.microsoft.com/en-us/library/windows/desktop/aa904937.aspx + // https://docs.microsoft.com/en-us/windows/desktop/Sync/slim-reader-writer--srw--locks if (type_ == kDynamic) { ::DeleteCriticalSection(critical_section_); delete critical_section_; @@ -279,6 +294,43 @@ void Mutex::AssertHeld() { << "The current thread is not holding the mutex @" << this; } +namespace { + +// Use the RAII idiom to flag mem allocs that are intentionally never +// deallocated. The motivation is to silence the false positive mem leaks +// that are reported by the debug version of MS's CRT which can only detect +// if an alloc is missing a matching deallocation. +// Example: +// MemoryIsNotDeallocated memory_is_not_deallocated; +// critical_section_ = new CRITICAL_SECTION; +// +class MemoryIsNotDeallocated +{ + public: + MemoryIsNotDeallocated() : old_crtdbg_flag_(0) { +#ifdef _MSC_VER + old_crtdbg_flag_ = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + // Set heap allocation block type to _IGNORE_BLOCK so that MS debug CRT + // doesn't report mem leak if there's no matching deallocation. + _CrtSetDbgFlag(old_crtdbg_flag_ & ~_CRTDBG_ALLOC_MEM_DF); +#endif // _MSC_VER + } + + ~MemoryIsNotDeallocated() { +#ifdef _MSC_VER + // Restore the original _CRTDBG_ALLOC_MEM_DF flag + _CrtSetDbgFlag(old_crtdbg_flag_); +#endif // _MSC_VER + } + + private: + int old_crtdbg_flag_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(MemoryIsNotDeallocated); +}; + +} // namespace + // Initializes owner_thread_id_ and critical_section_ in static mutexes. void Mutex::ThreadSafeLazyInit() { // Dynamic mutexes are initialized in the constructor. @@ -289,7 +341,11 @@ void Mutex::ThreadSafeLazyInit() { // If critical_section_init_phase_ was 0 before the exchange, we // are the first to test it and need to perform the initialization. owner_thread_id_ = 0; - critical_section_ = new CRITICAL_SECTION; + { + // Use RAII to flag that following mem alloc is never deallocated. + MemoryIsNotDeallocated memory_is_not_deallocated; + critical_section_ = new CRITICAL_SECTION; + } ::InitializeCriticalSection(critical_section_); // Updates the critical_section_init_phase_ to 2 to signal // initialization complete. @@ -328,7 +384,7 @@ class ThreadWithParamSupport : public ThreadWithParamBase { Notification* thread_can_start) { ThreadMainParam* param = new ThreadMainParam(runnable, thread_can_start); DWORD thread_id; - // TODO(yukawa): Consider to use _beginthreadex instead. + // FIXME: Consider to use _beginthreadex instead. HANDLE thread_handle = ::CreateThread( NULL, // Default security. 0, // Default stack size. @@ -496,7 +552,7 @@ class ThreadLocalRegistryImpl { FALSE, thread_id); GTEST_CHECK_(thread != NULL); - // We need to to pass a valid thread ID pointer into CreateThread for it + // We need to pass a valid thread ID pointer into CreateThread for it // to work correctly under Win98. DWORD watcher_thread_id; HANDLE watcher_thread = ::CreateThread( @@ -531,7 +587,8 @@ class ThreadLocalRegistryImpl { // Returns map of thread local instances. static ThreadIdToThreadLocals* GetThreadLocalsMapLocked() { mutex_.AssertHeld(); - static ThreadIdToThreadLocals* map = new ThreadIdToThreadLocals; + MemoryIsNotDeallocated memory_is_not_deallocated; + static ThreadIdToThreadLocals* map = new ThreadIdToThreadLocals(); return map; } @@ -671,7 +728,7 @@ bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { } // Helper function used by ValidateRegex() to format error messages. -std::string FormatRegexSyntaxError(const char* regex, int index) { +static std::string FormatRegexSyntaxError(const char* regex, int index) { return (Message() << "Syntax error at index " << index << " in simple regular expression \"" << regex << "\": ").GetString(); } @@ -680,7 +737,7 @@ std::string FormatRegexSyntaxError(const char* regex, int index) { // otherwise returns true. bool ValidateRegex(const char* regex) { if (regex == NULL) { - // TODO(wan@google.com): fix the source file location in the + // FIXME: fix the source file location in the // assertion failures to match where the regex is used in user // code. ADD_FAILURE() << "NULL is not a valid simple regular expression."; @@ -923,9 +980,10 @@ GTestLog::~GTestLog() { posix::Abort(); } } + // Disable Microsoft deprecation warnings for POSIX functions called from // this class (creat, dup, dup2, and close) -GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996) +GTEST_DISABLE_MSC_DEPRECATED_PUSH_() #if GTEST_HAS_STREAM_REDIRECTION @@ -1009,13 +1067,14 @@ class CapturedStream { GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream); }; -GTEST_DISABLE_MSC_WARNINGS_POP_() +GTEST_DISABLE_MSC_DEPRECATED_POP_() static CapturedStream* g_captured_stderr = NULL; static CapturedStream* g_captured_stdout = NULL; // Starts capturing an output stream (stdout/stderr). -void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { +static void CaptureStream(int fd, const char* stream_name, + CapturedStream** stream) { if (*stream != NULL) { GTEST_LOG_(FATAL) << "Only one " << stream_name << " capturer can exist at a time."; @@ -1024,7 +1083,7 @@ void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { } // Stops capturing the output stream and returns the captured string. -std::string GetCapturedStream(CapturedStream** captured_stream) { +static std::string GetCapturedStream(CapturedStream** captured_stream) { const std::string content = (*captured_stream)->GetCapturedString(); delete *captured_stream; @@ -1055,23 +1114,9 @@ std::string GetCapturedStderr() { #endif // GTEST_HAS_STREAM_REDIRECTION -std::string TempDir() { -#if GTEST_OS_WINDOWS_MOBILE - return "\\temp\\"; -#elif GTEST_OS_WINDOWS - const char* temp_dir = posix::GetEnv("TEMP"); - if (temp_dir == NULL || temp_dir[0] == '\0') - return "\\temp\\"; - else if (temp_dir[strlen(temp_dir) - 1] == '\\') - return temp_dir; - else - return std::string(temp_dir) + "\\"; -#elif GTEST_OS_LINUX_ANDROID - return "/sdcard/"; -#else - return "/tmp/"; -#endif // GTEST_OS_WINDOWS_MOBILE -} + + + size_t GetFileSize(FILE* file) { fseek(file, 0, SEEK_END); @@ -1101,22 +1146,36 @@ std::string ReadEntireFile(FILE* file) { } #if GTEST_HAS_DEATH_TEST +static const std::vector<std::string>* g_injected_test_argvs = NULL; // Owned. -static const ::std::vector<testing::internal::string>* g_injected_test_argvs = - NULL; // Owned. - -void SetInjectableArgvs(const ::std::vector<testing::internal::string>* argvs) { - if (g_injected_test_argvs != argvs) - delete g_injected_test_argvs; - g_injected_test_argvs = argvs; -} - -const ::std::vector<testing::internal::string>& GetInjectableArgvs() { +std::vector<std::string> GetInjectableArgvs() { if (g_injected_test_argvs != NULL) { return *g_injected_test_argvs; } return GetArgvs(); } + +void SetInjectableArgvs(const std::vector<std::string>* new_argvs) { + if (g_injected_test_argvs != new_argvs) delete g_injected_test_argvs; + g_injected_test_argvs = new_argvs; +} + +void SetInjectableArgvs(const std::vector<std::string>& new_argvs) { + SetInjectableArgvs( + new std::vector<std::string>(new_argvs.begin(), new_argvs.end())); +} + +#if GTEST_HAS_GLOBAL_STRING +void SetInjectableArgvs(const std::vector< ::string>& new_argvs) { + SetInjectableArgvs( + new std::vector<std::string>(new_argvs.begin(), new_argvs.end())); +} +#endif // GTEST_HAS_GLOBAL_STRING + +void ClearInjectableArgvs() { + delete g_injected_test_argvs; + g_injected_test_argvs = NULL; +} #endif // GTEST_HAS_DEATH_TEST #if GTEST_OS_WINDOWS_MOBILE @@ -1191,11 +1250,12 @@ bool ParseInt32(const Message& src_text, const char* str, Int32* value) { bool BoolFromGTestEnv(const char* flag, bool default_value) { #if defined(GTEST_GET_BOOL_FROM_ENV_) return GTEST_GET_BOOL_FROM_ENV_(flag, default_value); -#endif // defined(GTEST_GET_BOOL_FROM_ENV_) +#else const std::string env_var = FlagToEnvVar(flag); const char* const string_value = posix::GetEnv(env_var.c_str()); return string_value == NULL ? default_value : strcmp(string_value, "0") != 0; +#endif // defined(GTEST_GET_BOOL_FROM_ENV_) } // Reads and returns a 32-bit integer stored in the environment @@ -1204,7 +1264,7 @@ bool BoolFromGTestEnv(const char* flag, bool default_value) { Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { #if defined(GTEST_GET_INT32_FROM_ENV_) return GTEST_GET_INT32_FROM_ENV_(flag, default_value); -#endif // defined(GTEST_GET_INT32_FROM_ENV_) +#else const std::string env_var = FlagToEnvVar(flag); const char* const string_value = posix::GetEnv(env_var.c_str()); if (string_value == NULL) { @@ -1222,37 +1282,36 @@ Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { } return result; +#endif // defined(GTEST_GET_INT32_FROM_ENV_) +} + +// As a special case for the 'output' flag, if GTEST_OUTPUT is not +// set, we look for XML_OUTPUT_FILE, which is set by the Bazel build +// system. The value of XML_OUTPUT_FILE is a filename without the +// "xml:" prefix of GTEST_OUTPUT. +// Note that this is meant to be called at the call site so it does +// not check that the flag is 'output' +// In essence this checks an env variable called XML_OUTPUT_FILE +// and if it is set we prepend "xml:" to its value, if it not set we return "" +std::string OutputFlagAlsoCheckEnvVar(){ + std::string default_value_for_output_flag = ""; + const char* xml_output_file_env = posix::GetEnv("XML_OUTPUT_FILE"); + if (NULL != xml_output_file_env) { + default_value_for_output_flag = std::string("xml:") + xml_output_file_env; + } + return default_value_for_output_flag; } // Reads and returns the string environment variable corresponding to // the given flag; if it's not set, returns default_value. -std::string StringFromGTestEnv(const char* flag, const char* default_value) { +const char* StringFromGTestEnv(const char* flag, const char* default_value) { #if defined(GTEST_GET_STRING_FROM_ENV_) return GTEST_GET_STRING_FROM_ENV_(flag, default_value); -#endif // defined(GTEST_GET_STRING_FROM_ENV_) +#else const std::string env_var = FlagToEnvVar(flag); - const char* value = posix::GetEnv(env_var.c_str()); - if (value != NULL) { - return value; - } - - // As a special case for the 'output' flag, if GTEST_OUTPUT is not - // set, we look for XML_OUTPUT_FILE, which is set by the Bazel build - // system. The value of XML_OUTPUT_FILE is a filename without the - // "xml:" prefix of GTEST_OUTPUT. - // - // The net priority order after flag processing is thus: - // --gtest_output command line flag - // GTEST_OUTPUT environment variable - // XML_OUTPUT_FILE environment variable - // 'default_value' - if (strcmp(flag, "output") == 0) { - value = posix::GetEnv("XML_OUTPUT_FILE"); - if (value != NULL) { - return std::string("xml:") + value; - } - } - return default_value; + const char* const value = posix::GetEnv(env_var.c_str()); + return value == NULL ? default_value : value; +#endif // defined(GTEST_GET_STRING_FROM_ENV_) } } // namespace internal diff --git a/test/googletest/src/gtest-printers.cc b/test/googletest/src/gtest-printers.cc index a2df412f..de4d245e 100644 --- a/test/googletest/src/gtest-printers.cc +++ b/test/googletest/src/gtest-printers.cc @@ -26,10 +26,9 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) -// Google Test - The Google C++ Testing Framework + +// Google Test - The Google C++ Testing and Mocking Framework // // This file implements a universal value printer that can print a // value of any type T: @@ -43,12 +42,13 @@ // defines Foo. #include "gtest/gtest-printers.h" -#include <ctype.h> #include <stdio.h> +#include <cctype> #include <cwchar> #include <ostream> // NOLINT #include <string> #include "gtest/internal/gtest-port.h" +#include "src/gtest-internal-inl.h" namespace testing { @@ -89,7 +89,7 @@ void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, // If the object size is bigger than kThreshold, we'll have to omit // some details by printing only the first and the last kChunkSize // bytes. - // TODO(wan): let the user control the threshold using a flag. + // FIXME: let the user control the threshold using a flag. if (count < kThreshold) { PrintByteSegmentInObjectTo(obj_bytes, 0, count, os); } else { @@ -123,7 +123,7 @@ namespace internal { // Depending on the value of a char (or wchar_t), we print it in one // of three formats: // - as is if it's a printable ASCII (e.g. 'a', '2', ' '), -// - as a hexidecimal escape sequence (e.g. '\x7F'), or +// - as a hexadecimal escape sequence (e.g. '\x7F'), or // - as a special escape sequence (e.g. '\r', '\n'). enum CharFormat { kAsIs, @@ -180,7 +180,10 @@ static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { *os << static_cast<char>(c); return kAsIs; } else { - *os << "\\x" + String::FormatHexInt(static_cast<UnsignedChar>(c)); + ostream::fmtflags flags = os->flags(); + *os << "\\x" << std::hex << std::uppercase + << static_cast<int>(static_cast<UnsignedChar>(c)); + os->flags(flags); return kHexEscape; } } @@ -227,7 +230,7 @@ void PrintCharAndCodeTo(Char c, ostream* os) { return; *os << " (" << static_cast<int>(c); - // For more convenience, we print c's code again in hexidecimal, + // For more convenience, we print c's code again in hexadecimal, // unless c was already printed in the form '\x##' or the code is in // [1, 9]. if (format == kHexEscape || (1 <= c && c <= 9)) { @@ -259,11 +262,12 @@ template <typename CharType> GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ -static void PrintCharsAsStringTo( +static CharFormat PrintCharsAsStringTo( const CharType* begin, size_t len, ostream* os) { const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\""; *os << kQuoteBegin; bool is_previous_hex = false; + CharFormat print_format = kAsIs; for (size_t index = 0; index < len; ++index) { const CharType cur = begin[index]; if (is_previous_hex && IsXDigit(cur)) { @@ -273,8 +277,13 @@ static void PrintCharsAsStringTo( *os << "\" " << kQuoteBegin; } is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape; + // Remember if any characters required hex escaping. + if (is_previous_hex) { + print_format = kHexEscape; + } } *os << "\""; + return print_format; } // Prints a (const) char/wchar_t array of 'len' elements, starting at address @@ -344,15 +353,90 @@ void PrintTo(const wchar_t* s, ostream* os) { } #endif // wchar_t is native +namespace { + +bool ContainsUnprintableControlCodes(const char* str, size_t length) { + const unsigned char *s = reinterpret_cast<const unsigned char *>(str); + + for (size_t i = 0; i < length; i++) { + unsigned char ch = *s++; + if (std::iscntrl(ch)) { + switch (ch) { + case '\t': + case '\n': + case '\r': + break; + default: + return true; + } + } + } + return false; +} + +bool IsUTF8TrailByte(unsigned char t) { return 0x80 <= t && t<= 0xbf; } + +bool IsValidUTF8(const char* str, size_t length) { + const unsigned char *s = reinterpret_cast<const unsigned char *>(str); + + for (size_t i = 0; i < length;) { + unsigned char lead = s[i++]; + + if (lead <= 0x7f) { + continue; // single-byte character (ASCII) 0..7F + } + if (lead < 0xc2) { + return false; // trail byte or non-shortest form + } else if (lead <= 0xdf && (i + 1) <= length && IsUTF8TrailByte(s[i])) { + ++i; // 2-byte character + } else if (0xe0 <= lead && lead <= 0xef && (i + 2) <= length && + IsUTF8TrailByte(s[i]) && + IsUTF8TrailByte(s[i + 1]) && + // check for non-shortest form and surrogate + (lead != 0xe0 || s[i] >= 0xa0) && + (lead != 0xed || s[i] < 0xa0)) { + i += 2; // 3-byte character + } else if (0xf0 <= lead && lead <= 0xf4 && (i + 3) <= length && + IsUTF8TrailByte(s[i]) && + IsUTF8TrailByte(s[i + 1]) && + IsUTF8TrailByte(s[i + 2]) && + // check for non-shortest form + (lead != 0xf0 || s[i] >= 0x90) && + (lead != 0xf4 || s[i] < 0x90)) { + i += 3; // 4-byte character + } else { + return false; + } + } + return true; +} + +void ConditionalPrintAsText(const char* str, size_t length, ostream* os) { + if (!ContainsUnprintableControlCodes(str, length) && + IsValidUTF8(str, length)) { + *os << "\n As Text: \"" << str << "\""; + } +} + +} // anonymous namespace + // Prints a ::string object. #if GTEST_HAS_GLOBAL_STRING void PrintStringTo(const ::string& s, ostream* os) { - PrintCharsAsStringTo(s.data(), s.size(), os); + if (PrintCharsAsStringTo(s.data(), s.size(), os) == kHexEscape) { + if (GTEST_FLAG(print_utf8)) { + ConditionalPrintAsText(s.data(), s.size(), os); + } + } } #endif // GTEST_HAS_GLOBAL_STRING void PrintStringTo(const ::std::string& s, ostream* os) { - PrintCharsAsStringTo(s.data(), s.size(), os); + if (PrintCharsAsStringTo(s.data(), s.size(), os) == kHexEscape) { + if (GTEST_FLAG(print_utf8)) { + ConditionalPrintAsText(s.data(), s.size(), os); + } + } } // Prints a ::wstring object. diff --git a/test/googletest/src/gtest-test-part.cc b/test/googletest/src/gtest-test-part.cc index fb0e3542..c88860d9 100644 --- a/test/googletest/src/gtest-test-part.cc +++ b/test/googletest/src/gtest-test-part.cc @@ -26,21 +26,12 @@ // 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. + // -// Author: mheule@google.com (Markus Heule) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) #include "gtest/gtest-test-part.h" - -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick exists to -// prevent the accidental inclusion of gtest-internal-inl.h in the -// user's code. -#define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" -#undef GTEST_IMPLEMENTATION_ namespace testing { diff --git a/test/googletest/src/gtest-typed-test.cc b/test/googletest/src/gtest-typed-test.cc index df1eef47..1dc2ad38 100644 --- a/test/googletest/src/gtest-typed-test.cc +++ b/test/googletest/src/gtest-typed-test.cc @@ -26,10 +26,10 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) + #include "gtest/gtest-typed-test.h" + #include "gtest/gtest.h" namespace testing { diff --git a/test/googletest/src/gtest.cc b/test/googletest/src/gtest.cc index d882ab2e..96b07c68 100644 --- a/test/googletest/src/gtest.cc +++ b/test/googletest/src/gtest.cc @@ -26,10 +26,9 @@ // 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. + // -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) #include "gtest/gtest.h" #include "gtest/internal/custom/gtest.h" @@ -55,7 +54,7 @@ #if GTEST_OS_LINUX -// TODO(kenton@google.com): Use autoconf to detect availability of +// FIXME: Use autoconf to detect availability of // gettimeofday(). # define GTEST_HAS_GETTIMEOFDAY_ 1 @@ -94,9 +93,9 @@ # if GTEST_OS_WINDOWS_MINGW // MinGW has gettimeofday() but not _ftime64(). -// TODO(kenton@google.com): Use autoconf to detect availability of +// FIXME: Use autoconf to detect availability of // gettimeofday(). -// TODO(kenton@google.com): There are other ways to get the time on +// FIXME: There are other ways to get the time on // Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW // supports these. consider using them instead. # define GTEST_HAS_GETTIMEOFDAY_ 1 @@ -111,7 +110,7 @@ #else // Assume other platforms have gettimeofday(). -// TODO(kenton@google.com): Use autoconf to detect availability of +// FIXME: Use autoconf to detect availability of // gettimeofday(). # define GTEST_HAS_GETTIMEOFDAY_ 1 @@ -133,19 +132,25 @@ # include <sys/types.h> // NOLINT #endif -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. -#define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" -#undef GTEST_IMPLEMENTATION_ #if GTEST_OS_WINDOWS # define vsnprintf _vsnprintf #endif // GTEST_OS_WINDOWS +#if GTEST_OS_MAC +#ifndef GTEST_OS_IOS +#include <crt_externs.h> +#endif +#endif + +#if GTEST_HAS_ABSL +#include "absl/debugging/failure_signal_handler.h" +#include "absl/debugging/stacktrace.h" +#include "absl/debugging/symbolize.h" +#include "absl/strings/str_cat.h" +#endif // GTEST_HAS_ABSL + namespace testing { using internal::CountIf; @@ -167,8 +172,10 @@ static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*"; // A test filter that matches everything. static const char kUniversalFilter[] = "*"; -// The default output file for XML output. -static const char kDefaultOutputFile[] = "test_detail.xml"; +// The default output format. +static const char kDefaultOutputFormat[] = "xml"; +// The default output file. +static const char kDefaultOutputFile[] = "test_detail"; // The environment variable name for the test shard index. static const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; @@ -187,15 +194,31 @@ const char kStackTraceMarker[] = "\nStack trace:\n"; // specified on the command line. bool g_help_flag = false; +// Utilty function to Open File for Writing +static FILE* OpenFileForWriting(const std::string& output_file) { + FILE* fileout = NULL; + FilePath output_file_path(output_file); + FilePath output_dir(output_file_path.RemoveFileName()); + + if (output_dir.CreateDirectoriesRecursively()) { + fileout = posix::FOpen(output_file.c_str(), "w"); + } + if (fileout == NULL) { + GTEST_LOG_(FATAL) << "Unable to open file \"" << output_file << "\""; + } + return fileout; +} + } // namespace internal +// Bazel passes in the argument to '--test_filter' via the TESTBRIDGE_TEST_ONLY +// environment variable. static const char* GetDefaultFilter() { -#ifdef GTEST_TEST_FILTER_ENV_VAR_ - const char* const testbridge_test_only = getenv(GTEST_TEST_FILTER_ENV_VAR_); + const char* const testbridge_test_only = + internal::posix::GetEnv("TESTBRIDGE_TEST_ONLY"); if (testbridge_test_only != NULL) { return testbridge_test_only; } -#endif // GTEST_TEST_FILTER_ENV_VAR_ return kUniversalFilter; } @@ -232,15 +255,28 @@ GTEST_DEFINE_string_( "exclude). A test is run if it matches one of the positive " "patterns and does not match any of the negative patterns."); +GTEST_DEFINE_bool_( + install_failure_signal_handler, + internal::BoolFromGTestEnv("install_failure_signal_handler", false), + "If true and supported on the current platform, " GTEST_NAME_ " should " + "install a signal handler that dumps debugging information when fatal " + "signals are raised."); + GTEST_DEFINE_bool_(list_tests, false, "List all tests without running them."); +// The net priority order after flag processing is thus: +// --gtest_output command line flag +// GTEST_OUTPUT environment variable +// XML_OUTPUT_FILE environment variable +// '' GTEST_DEFINE_string_( output, - internal::StringFromGTestEnv("output", ""), - "A format (currently must be \"xml\"), optionally followed " - "by a colon and an output file name or directory. A directory " - "is indicated by a trailing pathname separator. " + internal::StringFromGTestEnv("output", + internal::OutputFlagAlsoCheckEnvVar().c_str()), + "A format (defaults to \"xml\" but can be specified to be \"json\"), " + "optionally followed by a colon and an output file name or directory. " + "A directory is indicated by a trailing pathname separator. " "Examples: \"xml:filename.xml\", \"xml::directoryname/\". " "If a directory is specified, output files will be created " "within that directory, with file-names based on the test " @@ -253,6 +289,12 @@ GTEST_DEFINE_bool_( "True iff " GTEST_NAME_ " should display elapsed time in text output."); +GTEST_DEFINE_bool_( + print_utf8, + internal::BoolFromGTestEnv("print_utf8", true), + "True iff " GTEST_NAME_ + " prints UTF8 characters as text."); + GTEST_DEFINE_int32_( random_seed, internal::Int32FromGTestEnv("random_seed", 0), @@ -294,7 +336,7 @@ GTEST_DEFINE_bool_( internal::BoolFromGTestEnv("throw_on_failure", false), "When this flag is specified, a failed assertion will throw an exception " "if exceptions are enabled or exit the program with a non-zero code " - "otherwise."); + "otherwise. For use with an external test framework."); #if GTEST_USE_OWN_FLAGFILE_FLAG_ GTEST_DEFINE_string_( @@ -310,7 +352,8 @@ namespace internal { // than kMaxRange. UInt32 Random::Generate(UInt32 range) { // These constants are the same as are used in glibc's rand(3). - state_ = (1103515245U*state_ + 12345U) % kMaxRange; + // Use wider types than necessary to prevent unsigned overflow diagnostics. + state_ = static_cast<UInt32>(1103515245ULL*state_ + 12345U) % kMaxRange; GTEST_CHECK_(range > 0) << "Cannot generate a number in the range [0, 0)."; @@ -384,12 +427,15 @@ void AssertHelper::operator=(const Message& message) const { GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); // A copy of all command line arguments. Set by InitGoogleTest(). -::std::vector<testing::internal::string> g_argvs; +static ::std::vector<std::string> g_argvs; -const ::std::vector<testing::internal::string>& GetArgvs() { +::std::vector<std::string> GetArgvs() { #if defined(GTEST_CUSTOM_GET_ARGVS_) - return GTEST_CUSTOM_GET_ARGVS_(); -#else // defined(GTEST_CUSTOM_GET_ARGVS_) + // GTEST_CUSTOM_GET_ARGVS_() may return a container of std::string or + // ::string. This code converts it to the appropriate type. + const auto& custom = GTEST_CUSTOM_GET_ARGVS_(); + return ::std::vector<std::string>(custom.begin(), custom.end()); +#else // defined(GTEST_CUSTOM_GET_ARGVS_) return g_argvs; #endif // defined(GTEST_CUSTOM_GET_ARGVS_) } @@ -413,8 +459,6 @@ FilePath GetCurrentExecutableName() { // Returns the output format, or "" for normal printed output. std::string UnitTestOptions::GetOutputFormat() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); - if (gtest_output_flag == NULL) return std::string(""); - const char* const colon = strchr(gtest_output_flag, ':'); return (colon == NULL) ? std::string(gtest_output_flag) : @@ -425,19 +469,22 @@ std::string UnitTestOptions::GetOutputFormat() { // was explicitly specified. std::string UnitTestOptions::GetAbsolutePathToOutputFile() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); - if (gtest_output_flag == NULL) - return ""; + + std::string format = GetOutputFormat(); + if (format.empty()) + format = std::string(kDefaultOutputFormat); const char* const colon = strchr(gtest_output_flag, ':'); if (colon == NULL) - return internal::FilePath::ConcatPaths( + return internal::FilePath::MakeFileName( internal::FilePath( UnitTest::GetInstance()->original_working_dir()), - internal::FilePath(kDefaultOutputFile)).string(); + internal::FilePath(kDefaultOutputFile), 0, + format.c_str()).string(); internal::FilePath output_name(colon + 1); if (!output_name.IsAbsolutePath()) - // TODO(wan@google.com): on Windows \some\path is not an absolute + // FIXME: on Windows \some\path is not an absolute // path (as its meaning depends on the current drive), yet the // following logic for turning it into an absolute path is wrong. // Fix it. @@ -628,12 +675,12 @@ extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId(); // This predicate-formatter checks that 'results' contains a test part // failure of the given type and that the failure message contains the // given substring. -AssertionResult HasOneFailure(const char* /* results_expr */, - const char* /* type_expr */, - const char* /* substr_expr */, - const TestPartResultArray& results, - TestPartResult::Type type, - const string& substr) { +static AssertionResult HasOneFailure(const char* /* results_expr */, + const char* /* type_expr */, + const char* /* substr_expr */, + const TestPartResultArray& results, + TestPartResult::Type type, + const std::string& substr) { const std::string expected(type == TestPartResult::kFatalFailure ? "1 fatal failure" : "1 non-fatal failure"); @@ -667,13 +714,10 @@ AssertionResult HasOneFailure(const char* /* results_expr */, // The constructor of SingleFailureChecker remembers where to look up // test part results, what type of failure we expect, and what // substring the failure message should contain. -SingleFailureChecker:: SingleFailureChecker( - const TestPartResultArray* results, - TestPartResult::Type type, - const string& substr) - : results_(results), - type_(type), - substr_(substr) {} +SingleFailureChecker::SingleFailureChecker(const TestPartResultArray* results, + TestPartResult::Type type, + const std::string& substr) + : results_(results), type_(type), substr_(substr) {} // The destructor of SingleFailureChecker verifies that the given // TestPartResultArray contains exactly one failure that has the given @@ -814,7 +858,7 @@ TimeInMillis GetTimeInMillis() { SYSTEMTIME now_systime; FILETIME now_filetime; ULARGE_INTEGER now_int64; - // TODO(kenton@google.com): Shouldn't this just use + // FIXME: Shouldn't this just use // GetSystemTimeAsFileTime()? GetSystemTime(&now_systime); if (SystemTimeToFileTime(&now_systime, &now_filetime)) { @@ -830,11 +874,11 @@ TimeInMillis GetTimeInMillis() { // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 // (deprecated function) there. - // TODO(kenton@google.com): Use GetTickCount()? Or use + // FIXME: Use GetTickCount()? Or use // SystemTimeToFileTime() - GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996) + GTEST_DISABLE_MSC_DEPRECATED_PUSH_() _ftime64(&now); - GTEST_DISABLE_MSC_WARNINGS_POP_() + GTEST_DISABLE_MSC_DEPRECATED_POP_() return static_cast<TimeInMillis>(now.time) * 1000 + now.millitm; #elif GTEST_HAS_GETTIMEOFDAY_ @@ -1171,7 +1215,7 @@ class Hunk { // Print a unified diff header for one hunk. // The format is // "@@ -<left_start>,<left_length> +<right_start>,<right_length> @@" - // where the left/right parts are ommitted if unnecessary. + // where the left/right parts are omitted if unnecessary. void PrintHeader(std::ostream* ss) const { *ss << "@@ "; if (removes_) { @@ -1315,13 +1359,14 @@ AssertionResult EqFailure(const char* lhs_expression, const std::string& rhs_value, bool ignoring_case) { Message msg; - msg << " Expected: " << lhs_expression; + msg << "Expected equality of these values:"; + msg << "\n " << lhs_expression; if (lhs_value != lhs_expression) { - msg << "\n Which is: " << lhs_value; + msg << "\n Which is: " << lhs_value; } - msg << "\nTo be equal to: " << rhs_expression; + msg << "\n " << rhs_expression; if (rhs_value != rhs_expression) { - msg << "\n Which is: " << rhs_value; + msg << "\n Which is: " << rhs_value; } if (ignoring_case) { @@ -1368,7 +1413,7 @@ AssertionResult DoubleNearPredFormat(const char* expr1, const double diff = fabs(val1 - val2); if (diff <= abs_error) return AssertionSuccess(); - // TODO(wan): do not print the value of an expression if it's + // FIXME: do not print the value of an expression if it's // already a literal. return AssertionFailure() << "The difference between " << expr1 << " and " << expr2 @@ -1663,7 +1708,7 @@ namespace { AssertionResult HRESULTFailureHelper(const char* expr, const char* expected, long hr) { // NOLINT -# if GTEST_OS_WINDOWS_MOBILE +# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_TV_TITLE // Windows CE doesn't support FormatMessage. const char error_text[] = ""; @@ -1720,7 +1765,7 @@ AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT // Utility functions for encoding Unicode text (wide strings) in // UTF-8. -// A Unicode code-point can have upto 21 bits, and is encoded in UTF-8 +// A Unicode code-point can have up to 21 bits, and is encoded in UTF-8 // like this: // // Code-point length Encoding @@ -1784,7 +1829,7 @@ std::string CodePointToUtf8(UInt32 code_point) { return str; } -// The following two functions only make sense if the the system +// The following two functions only make sense if the system // uses UTF-16 for wide string encoding. All supported systems // with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16. @@ -2096,13 +2141,8 @@ static const char* const kReservedTestSuiteAttributes[] = { // The list of reserved attributes used in the <testcase> element of XML output. static const char* const kReservedTestCaseAttributes[] = { - "classname", - "name", - "status", - "time", - "type_param", - "value_param" -}; + "classname", "name", "status", "time", + "type_param", "value_param", "file", "line"}; template <int kSize> std::vector<std::string> ArrayAsVector(const char* const (&array)[kSize]) { @@ -2138,8 +2178,9 @@ static std::string FormatWordList(const std::vector<std::string>& words) { return word_list.GetString(); } -bool ValidateTestPropertyName(const std::string& property_name, - const std::vector<std::string>& reserved_names) { +static bool ValidateTestPropertyName( + const std::string& property_name, + const std::vector<std::string>& reserved_names) { if (std::find(reserved_names.begin(), reserved_names.end(), property_name) != reserved_names.end()) { ADD_FAILURE() << "Reserved key used in RecordProperty(): " << property_name @@ -2436,6 +2477,8 @@ Result HandleExceptionsInMethodIfSupported( #if GTEST_HAS_EXCEPTIONS try { return HandleSehExceptionsInMethodIfSupported(object, method, location); + } catch (const AssertionException&) { // NOLINT + // This failure was reported already. } catch (const internal::GoogleTestFailureException&) { // NOLINT // This exception type can only be thrown by a failed Google // Test assertion with the intention of letting another testing @@ -2557,7 +2600,6 @@ TestInfo* MakeAndRegisterTestInfo( return test_info; } -#if GTEST_HAS_PARAM_TEST void ReportInvalidTestCaseType(const char* test_case_name, CodeLocation code_location) { Message errors; @@ -2571,13 +2613,10 @@ void ReportInvalidTestCaseType(const char* test_case_name, << "probably rename one of the classes to put the tests into different\n" << "test cases."; - fprintf(stderr, "%s %s", - FormatFileLocation(code_location.file.c_str(), - code_location.line).c_str(), - errors.GetString().c_str()); + GTEST_LOG_(ERROR) << FormatFileLocation(code_location.file.c_str(), + code_location.line) + << " " << errors.GetString(); } -#endif // GTEST_HAS_PARAM_TEST - } // namespace internal namespace { @@ -2615,12 +2654,10 @@ namespace internal { // and INSTANTIATE_TEST_CASE_P into regular tests and registers those. // This will be done just once during the program runtime. void UnitTestImpl::RegisterParameterizedTests() { -#if GTEST_HAS_PARAM_TEST if (!parameterized_tests_registered_) { parameterized_test_registry_.RegisterTests(); parameterized_tests_registered_ = true; } -#endif } } // namespace internal @@ -2648,18 +2685,18 @@ void TestInfo::Run() { factory_, &internal::TestFactoryBase::CreateTest, "the test fixture's constructor"); - // Runs the test only if the test object was created and its - // constructor didn't generate a fatal failure. - if ((test != NULL) && !Test::HasFatalFailure()) { + // Runs the test if the constructor didn't generate a fatal failure. + // Note that the object will not be null + if (!Test::HasFatalFailure()) { // This doesn't throw as all user code that can throw are wrapped into // exception handling code. test->Run(); } - // Deletes the test object. - impl->os_stack_trace_getter()->UponLeavingGTest(); - internal::HandleExceptionsInMethodIfSupported( - test, &Test::DeleteSelf_, "the test fixture's destructor"); + // Deletes the test object. + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + test, &Test::DeleteSelf_, "the test fixture's destructor"); result_.set_elapsed_time(internal::GetTimeInMillis() - start); @@ -2885,10 +2922,10 @@ enum GTestColor { }; #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \ - !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT + !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT && !GTEST_OS_WINDOWS_MINGW // Returns the character attribute for the given color. -WORD GetColorAttribute(GTestColor color) { +static WORD GetColorAttribute(GTestColor color) { switch (color) { case COLOR_RED: return FOREGROUND_RED; case COLOR_GREEN: return FOREGROUND_GREEN; @@ -2897,11 +2934,42 @@ WORD GetColorAttribute(GTestColor color) { } } +static int GetBitOffset(WORD color_mask) { + if (color_mask == 0) return 0; + + int bitOffset = 0; + while ((color_mask & 1) == 0) { + color_mask >>= 1; + ++bitOffset; + } + return bitOffset; +} + +static WORD GetNewColor(GTestColor color, WORD old_color_attrs) { + // Let's reuse the BG + static const WORD background_mask = BACKGROUND_BLUE | BACKGROUND_GREEN | + BACKGROUND_RED | BACKGROUND_INTENSITY; + static const WORD foreground_mask = FOREGROUND_BLUE | FOREGROUND_GREEN | + FOREGROUND_RED | FOREGROUND_INTENSITY; + const WORD existing_bg = old_color_attrs & background_mask; + + WORD new_color = + GetColorAttribute(color) | existing_bg | FOREGROUND_INTENSITY; + static const int bg_bitOffset = GetBitOffset(background_mask); + static const int fg_bitOffset = GetBitOffset(foreground_mask); + + if (((new_color & background_mask) >> bg_bitOffset) == + ((new_color & foreground_mask) >> fg_bitOffset)) { + new_color ^= FOREGROUND_INTENSITY; // invert intensity + } + return new_color; +} + #else // Returns the ANSI color code for the given color. COLOR_DEFAULT is // an invalid input. -const char* GetAnsiColorCode(GTestColor color) { +static const char* GetAnsiColorCode(GTestColor color) { switch (color) { case COLOR_RED: return "1"; case COLOR_GREEN: return "2"; @@ -2917,7 +2985,7 @@ bool ShouldUseColor(bool stdout_is_tty) { const char* const gtest_color = GTEST_FLAG(color).c_str(); if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { -#if GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW // On Windows the TERM variable is usually not set, but the // console there does support colors. return stdout_is_tty; @@ -2953,7 +3021,7 @@ bool ShouldUseColor(bool stdout_is_tty) { // cannot simply emit special characters and have the terminal change colors. // This routine must actually emit the characters rather than return a string // that would be colored when printed, as can be done on Linux. -void ColoredPrintf(GTestColor color, const char* fmt, ...) { +static void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_list args; va_start(args, fmt); @@ -2974,20 +3042,21 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { } #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \ - !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT + !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT && !GTEST_OS_WINDOWS_MINGW const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); // Gets the current text color. CONSOLE_SCREEN_BUFFER_INFO buffer_info; GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); const WORD old_color_attrs = buffer_info.wAttributes; + const WORD new_color = GetNewColor(color, old_color_attrs); // We need to flush the stream buffers into the console before each // SetConsoleTextAttribute call lest it affect the text that is already // printed but has not yet reached the console. fflush(stdout); - SetConsoleTextAttribute(stdout_handle, - GetColorAttribute(color) | FOREGROUND_INTENSITY); + SetConsoleTextAttribute(stdout_handle, new_color); + vprintf(fmt, args); fflush(stdout); @@ -3001,12 +3070,12 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_end(args); } -// Text printed in Google Test's text output and --gunit_list_tests +// Text printed in Google Test's text output and --gtest_list_tests // output to label the type parameter and value parameter for a test. static const char kTypeParamLabel[] = "TypeParam"; static const char kValueParamLabel[] = "GetParam()"; -void PrintFullTestCommentIfPresent(const TestInfo& test_info) { +static void PrintFullTestCommentIfPresent(const TestInfo& test_info) { const char* const type_param = test_info.type_param(); const char* const value_param = test_info.value_param(); @@ -3277,7 +3346,7 @@ void TestEventRepeater::Append(TestEventListener *listener) { listeners_.push_back(listener); } -// TODO(vladl@google.com): Factor the search functionality into Vector::Find. +// FIXME: Factor the search functionality into Vector::Find. TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { for (size_t i = 0; i < listeners_.size(); ++i) { if (listeners_[i] == listener) { @@ -3351,6 +3420,11 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { explicit XmlUnitTestResultPrinter(const char* output_file); virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + void ListTestsMatchingFilter(const std::vector<TestCase*>& test_cases); + + // Prints an XML summary of all unit tests. + static void PrintXmlTestsList(std::ostream* stream, + const std::vector<TestCase*>& test_cases); private: // Is c a whitespace character that is normalized to a space character @@ -3412,6 +3486,11 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { // to delimit this attribute from prior attributes. static std::string TestPropertiesAsXmlAttributes(const TestResult& result); + // Streams an XML representation of the test properties of a TestResult + // object. + static void OutputXmlTestProperties(std::ostream* stream, + const TestResult& result); + // The output file. const std::string output_file_; @@ -3421,46 +3500,30 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { // Creates a new XmlUnitTestResultPrinter. XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) : output_file_(output_file) { - if (output_file_.c_str() == NULL || output_file_.empty()) { - fprintf(stderr, "XML output file may not be null\n"); - fflush(stderr); - exit(EXIT_FAILURE); + if (output_file_.empty()) { + GTEST_LOG_(FATAL) << "XML output file may not be null"; } } // Called after the unit test ends. void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, int /*iteration*/) { - FILE* xmlout = NULL; - FilePath output_file(output_file_); - FilePath output_dir(output_file.RemoveFileName()); - - if (output_dir.CreateDirectoriesRecursively()) { - xmlout = posix::FOpen(output_file_.c_str(), "w"); - } - if (xmlout == NULL) { - // TODO(wan): report the reason of the failure. - // - // We don't do it for now as: - // - // 1. There is no urgent need for it. - // 2. It's a bit involved to make the errno variable thread-safe on - // all three operating systems (Linux, Windows, and Mac OS). - // 3. To interpret the meaning of errno in a thread-safe way, - // we need the strerror_r() function, which is not available on - // Windows. - fprintf(stderr, - "Unable to open file \"%s\"\n", - output_file_.c_str()); - fflush(stderr); - exit(EXIT_FAILURE); - } + FILE* xmlout = OpenFileForWriting(output_file_); std::stringstream stream; PrintXmlUnitTest(&stream, unit_test); fprintf(xmlout, "%s", StringStreamToString(&stream).c_str()); fclose(xmlout); } +void XmlUnitTestResultPrinter::ListTestsMatchingFilter( + const std::vector<TestCase*>& test_cases) { + FILE* xmlout = OpenFileForWriting(output_file_); + std::stringstream stream; + PrintXmlTestsList(&stream, test_cases); + fprintf(xmlout, "%s", StringStreamToString(&stream).c_str()); + fclose(xmlout); +} + // Returns an XML-escaped copy of the input string str. If is_attribute // is true, the text is meant to appear as an attribute value, and // normalizable whitespace is preserved by replacing it with character @@ -3471,7 +3534,7 @@ void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, // module will consist of ordinary English text. // If this module is ever modified to produce version 1.1 XML output, // most invalid characters can be retained using character references. -// TODO(wan): It might be nice to have a minimally invasive, human-readable +// FIXME: It might be nice to have a minimally invasive, human-readable // escaping scheme for invalid characters, rather than dropping them. std::string XmlUnitTestResultPrinter::EscapeXml( const std::string& str, bool is_attribute) { @@ -3532,6 +3595,7 @@ std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters( // The following routines generate an XML representation of a UnitTest // object. +// GOOGLETEST_CM0009 DO NOT DELETE // // This is how Google Test concepts map to the DTD: // @@ -3621,13 +3685,17 @@ void XmlUnitTestResultPrinter::OutputXmlAttribute( } // Prints an XML representation of a TestInfo object. -// TODO(wan): There is also value in printing properties with the plain printer. +// FIXME: There is also value in printing properties with the plain printer. void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, const char* test_case_name, const TestInfo& test_info) { const TestResult& result = *test_info.result(); const std::string kTestcase = "testcase"; + if (test_info.is_in_another_shard()) { + return; + } + *stream << " <testcase"; OutputXmlAttribute(stream, kTestcase, "name", test_info.name()); @@ -3638,13 +3706,19 @@ void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, if (test_info.type_param() != NULL) { OutputXmlAttribute(stream, kTestcase, "type_param", test_info.type_param()); } + if (GTEST_FLAG(list_tests)) { + OutputXmlAttribute(stream, kTestcase, "file", test_info.file()); + OutputXmlAttribute(stream, kTestcase, "line", + StreamableToString(test_info.line())); + *stream << " />\n"; + return; + } OutputXmlAttribute(stream, kTestcase, "status", test_info.should_run() ? "run" : "notrun"); OutputXmlAttribute(stream, kTestcase, "time", FormatTimeInMillisAsSeconds(result.elapsed_time())); OutputXmlAttribute(stream, kTestcase, "classname", test_case_name); - *stream << TestPropertiesAsXmlAttributes(result); int failures = 0; for (int i = 0; i < result.total_part_count(); ++i) { @@ -3653,22 +3727,28 @@ void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, if (++failures == 1) { *stream << ">\n"; } - const string location = internal::FormatCompilerIndependentFileLocation( - part.file_name(), part.line_number()); - const string summary = location + "\n" + part.summary(); + const std::string location = + internal::FormatCompilerIndependentFileLocation(part.file_name(), + part.line_number()); + const std::string summary = location + "\n" + part.summary(); *stream << " <failure message=\"" << EscapeXmlAttribute(summary.c_str()) << "\" type=\"\">"; - const string detail = location + "\n" + part.message(); + const std::string detail = location + "\n" + part.message(); OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str()); *stream << "</failure>\n"; } } - if (failures == 0) + if (failures == 0 && result.test_property_count() == 0) { *stream << " />\n"; - else + } else { + if (failures == 0) { + *stream << ">\n"; + } + OutputXmlTestProperties(stream, result); *stream << " </testcase>\n"; + } } // Prints an XML representation of a TestCase object @@ -3679,17 +3759,18 @@ void XmlUnitTestResultPrinter::PrintXmlTestCase(std::ostream* stream, OutputXmlAttribute(stream, kTestsuite, "name", test_case.name()); OutputXmlAttribute(stream, kTestsuite, "tests", StreamableToString(test_case.reportable_test_count())); - OutputXmlAttribute(stream, kTestsuite, "failures", - StreamableToString(test_case.failed_test_count())); - OutputXmlAttribute( - stream, kTestsuite, "disabled", - StreamableToString(test_case.reportable_disabled_test_count())); - OutputXmlAttribute(stream, kTestsuite, "errors", "0"); - OutputXmlAttribute(stream, kTestsuite, "time", - FormatTimeInMillisAsSeconds(test_case.elapsed_time())); - *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result()) - << ">\n"; - + if (!GTEST_FLAG(list_tests)) { + OutputXmlAttribute(stream, kTestsuite, "failures", + StreamableToString(test_case.failed_test_count())); + OutputXmlAttribute( + stream, kTestsuite, "disabled", + StreamableToString(test_case.reportable_disabled_test_count())); + OutputXmlAttribute(stream, kTestsuite, "errors", "0"); + OutputXmlAttribute(stream, kTestsuite, "time", + FormatTimeInMillisAsSeconds(test_case.elapsed_time())); + *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result()); + } + *stream << ">\n"; for (int i = 0; i < test_case.total_test_count(); ++i) { if (test_case.GetTestInfo(i)->is_reportable()) OutputXmlTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i)); @@ -3723,7 +3804,6 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, OutputXmlAttribute(stream, kTestsuites, "random_seed", StreamableToString(unit_test.random_seed())); } - *stream << TestPropertiesAsXmlAttributes(unit_test.ad_hoc_test_result()); OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); @@ -3736,6 +3816,28 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, *stream << "</" << kTestsuites << ">\n"; } +void XmlUnitTestResultPrinter::PrintXmlTestsList( + std::ostream* stream, const std::vector<TestCase*>& test_cases) { + const std::string kTestsuites = "testsuites"; + + *stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; + *stream << "<" << kTestsuites; + + int total_tests = 0; + for (size_t i = 0; i < test_cases.size(); ++i) { + total_tests += test_cases[i]->total_test_count(); + } + OutputXmlAttribute(stream, kTestsuites, "tests", + StreamableToString(total_tests)); + OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); + *stream << ">\n"; + + for (size_t i = 0; i < test_cases.size(); ++i) { + PrintXmlTestCase(stream, *test_cases[i]); + } + *stream << "</" << kTestsuites << ">\n"; +} + // Produces a string representing the test properties in a result as space // delimited XML attributes based on the property key="value" pairs. std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( @@ -3749,8 +3851,390 @@ std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( return attributes.GetString(); } +void XmlUnitTestResultPrinter::OutputXmlTestProperties( + std::ostream* stream, const TestResult& result) { + const std::string kProperties = "properties"; + const std::string kProperty = "property"; + + if (result.test_property_count() <= 0) { + return; + } + + *stream << "<" << kProperties << ">\n"; + for (int i = 0; i < result.test_property_count(); ++i) { + const TestProperty& property = result.GetTestProperty(i); + *stream << "<" << kProperty; + *stream << " name=\"" << EscapeXmlAttribute(property.key()) << "\""; + *stream << " value=\"" << EscapeXmlAttribute(property.value()) << "\""; + *stream << "/>\n"; + } + *stream << "</" << kProperties << ">\n"; +} + // End XmlUnitTestResultPrinter +// This class generates an JSON output file. +class JsonUnitTestResultPrinter : public EmptyTestEventListener { + public: + explicit JsonUnitTestResultPrinter(const char* output_file); + + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + + // Prints an JSON summary of all unit tests. + static void PrintJsonTestList(::std::ostream* stream, + const std::vector<TestCase*>& test_cases); + + private: + // Returns an JSON-escaped copy of the input string str. + static std::string EscapeJson(const std::string& str); + + //// Verifies that the given attribute belongs to the given element and + //// streams the attribute as JSON. + static void OutputJsonKey(std::ostream* stream, + const std::string& element_name, + const std::string& name, + const std::string& value, + const std::string& indent, + bool comma = true); + static void OutputJsonKey(std::ostream* stream, + const std::string& element_name, + const std::string& name, + int value, + const std::string& indent, + bool comma = true); + + // Streams a JSON representation of a TestInfo object. + static void OutputJsonTestInfo(::std::ostream* stream, + const char* test_case_name, + const TestInfo& test_info); + + // Prints a JSON representation of a TestCase object + static void PrintJsonTestCase(::std::ostream* stream, + const TestCase& test_case); + + // Prints a JSON summary of unit_test to output stream out. + static void PrintJsonUnitTest(::std::ostream* stream, + const UnitTest& unit_test); + + // Produces a string representing the test properties in a result as + // a JSON dictionary. + static std::string TestPropertiesAsJson(const TestResult& result, + const std::string& indent); + + // The output file. + const std::string output_file_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(JsonUnitTestResultPrinter); +}; + +// Creates a new JsonUnitTestResultPrinter. +JsonUnitTestResultPrinter::JsonUnitTestResultPrinter(const char* output_file) + : output_file_(output_file) { + if (output_file_.empty()) { + GTEST_LOG_(FATAL) << "JSON output file may not be null"; + } +} + +void JsonUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { + FILE* jsonout = OpenFileForWriting(output_file_); + std::stringstream stream; + PrintJsonUnitTest(&stream, unit_test); + fprintf(jsonout, "%s", StringStreamToString(&stream).c_str()); + fclose(jsonout); +} + +// Returns an JSON-escaped copy of the input string str. +std::string JsonUnitTestResultPrinter::EscapeJson(const std::string& str) { + Message m; + + for (size_t i = 0; i < str.size(); ++i) { + const char ch = str[i]; + switch (ch) { + case '\\': + case '"': + case '/': + m << '\\' << ch; + break; + case '\b': + m << "\\b"; + break; + case '\t': + m << "\\t"; + break; + case '\n': + m << "\\n"; + break; + case '\f': + m << "\\f"; + break; + case '\r': + m << "\\r"; + break; + default: + if (ch < ' ') { + m << "\\u00" << String::FormatByte(static_cast<unsigned char>(ch)); + } else { + m << ch; + } + break; + } + } + + return m.GetString(); +} + +// The following routines generate an JSON representation of a UnitTest +// object. + +// Formats the given time in milliseconds as seconds. +static std::string FormatTimeInMillisAsDuration(TimeInMillis ms) { + ::std::stringstream ss; + ss << (static_cast<double>(ms) * 1e-3) << "s"; + return ss.str(); +} + +// Converts the given epoch time in milliseconds to a date string in the +// RFC3339 format, without the timezone information. +static std::string FormatEpochTimeInMillisAsRFC3339(TimeInMillis ms) { + struct tm time_struct; + if (!PortableLocaltime(static_cast<time_t>(ms / 1000), &time_struct)) + return ""; + // YYYY-MM-DDThh:mm:ss + return StreamableToString(time_struct.tm_year + 1900) + "-" + + String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" + + String::FormatIntWidth2(time_struct.tm_mday) + "T" + + String::FormatIntWidth2(time_struct.tm_hour) + ":" + + String::FormatIntWidth2(time_struct.tm_min) + ":" + + String::FormatIntWidth2(time_struct.tm_sec) + "Z"; +} + +static inline std::string Indent(int width) { + return std::string(width, ' '); +} + +void JsonUnitTestResultPrinter::OutputJsonKey( + std::ostream* stream, + const std::string& element_name, + const std::string& name, + const std::string& value, + const std::string& indent, + bool comma) { + const std::vector<std::string>& allowed_names = + GetReservedAttributesForElement(element_name); + + GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != + allowed_names.end()) + << "Key \"" << name << "\" is not allowed for value \"" << element_name + << "\"."; + + *stream << indent << "\"" << name << "\": \"" << EscapeJson(value) << "\""; + if (comma) + *stream << ",\n"; +} + +void JsonUnitTestResultPrinter::OutputJsonKey( + std::ostream* stream, + const std::string& element_name, + const std::string& name, + int value, + const std::string& indent, + bool comma) { + const std::vector<std::string>& allowed_names = + GetReservedAttributesForElement(element_name); + + GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != + allowed_names.end()) + << "Key \"" << name << "\" is not allowed for value \"" << element_name + << "\"."; + + *stream << indent << "\"" << name << "\": " << StreamableToString(value); + if (comma) + *stream << ",\n"; +} + +// Prints a JSON representation of a TestInfo object. +void JsonUnitTestResultPrinter::OutputJsonTestInfo(::std::ostream* stream, + const char* test_case_name, + const TestInfo& test_info) { + const TestResult& result = *test_info.result(); + const std::string kTestcase = "testcase"; + const std::string kIndent = Indent(10); + + *stream << Indent(8) << "{\n"; + OutputJsonKey(stream, kTestcase, "name", test_info.name(), kIndent); + + if (test_info.value_param() != NULL) { + OutputJsonKey(stream, kTestcase, "value_param", + test_info.value_param(), kIndent); + } + if (test_info.type_param() != NULL) { + OutputJsonKey(stream, kTestcase, "type_param", test_info.type_param(), + kIndent); + } + if (GTEST_FLAG(list_tests)) { + OutputJsonKey(stream, kTestcase, "file", test_info.file(), kIndent); + OutputJsonKey(stream, kTestcase, "line", test_info.line(), kIndent, false); + *stream << "\n" << Indent(8) << "}"; + return; + } + + OutputJsonKey(stream, kTestcase, "status", + test_info.should_run() ? "RUN" : "NOTRUN", kIndent); + OutputJsonKey(stream, kTestcase, "time", + FormatTimeInMillisAsDuration(result.elapsed_time()), kIndent); + OutputJsonKey(stream, kTestcase, "classname", test_case_name, kIndent, false); + *stream << TestPropertiesAsJson(result, kIndent); + + int failures = 0; + for (int i = 0; i < result.total_part_count(); ++i) { + const TestPartResult& part = result.GetTestPartResult(i); + if (part.failed()) { + *stream << ",\n"; + if (++failures == 1) { + *stream << kIndent << "\"" << "failures" << "\": [\n"; + } + const std::string location = + internal::FormatCompilerIndependentFileLocation(part.file_name(), + part.line_number()); + const std::string message = EscapeJson(location + "\n" + part.message()); + *stream << kIndent << " {\n" + << kIndent << " \"failure\": \"" << message << "\",\n" + << kIndent << " \"type\": \"\"\n" + << kIndent << " }"; + } + } + + if (failures > 0) + *stream << "\n" << kIndent << "]"; + *stream << "\n" << Indent(8) << "}"; +} + +// Prints an JSON representation of a TestCase object +void JsonUnitTestResultPrinter::PrintJsonTestCase(std::ostream* stream, + const TestCase& test_case) { + const std::string kTestsuite = "testsuite"; + const std::string kIndent = Indent(6); + + *stream << Indent(4) << "{\n"; + OutputJsonKey(stream, kTestsuite, "name", test_case.name(), kIndent); + OutputJsonKey(stream, kTestsuite, "tests", test_case.reportable_test_count(), + kIndent); + if (!GTEST_FLAG(list_tests)) { + OutputJsonKey(stream, kTestsuite, "failures", test_case.failed_test_count(), + kIndent); + OutputJsonKey(stream, kTestsuite, "disabled", + test_case.reportable_disabled_test_count(), kIndent); + OutputJsonKey(stream, kTestsuite, "errors", 0, kIndent); + OutputJsonKey(stream, kTestsuite, "time", + FormatTimeInMillisAsDuration(test_case.elapsed_time()), + kIndent, false); + *stream << TestPropertiesAsJson(test_case.ad_hoc_test_result(), kIndent) + << ",\n"; + } + + *stream << kIndent << "\"" << kTestsuite << "\": [\n"; + + bool comma = false; + for (int i = 0; i < test_case.total_test_count(); ++i) { + if (test_case.GetTestInfo(i)->is_reportable()) { + if (comma) { + *stream << ",\n"; + } else { + comma = true; + } + OutputJsonTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i)); + } + } + *stream << "\n" << kIndent << "]\n" << Indent(4) << "}"; +} + +// Prints a JSON summary of unit_test to output stream out. +void JsonUnitTestResultPrinter::PrintJsonUnitTest(std::ostream* stream, + const UnitTest& unit_test) { + const std::string kTestsuites = "testsuites"; + const std::string kIndent = Indent(2); + *stream << "{\n"; + + OutputJsonKey(stream, kTestsuites, "tests", unit_test.reportable_test_count(), + kIndent); + OutputJsonKey(stream, kTestsuites, "failures", unit_test.failed_test_count(), + kIndent); + OutputJsonKey(stream, kTestsuites, "disabled", + unit_test.reportable_disabled_test_count(), kIndent); + OutputJsonKey(stream, kTestsuites, "errors", 0, kIndent); + if (GTEST_FLAG(shuffle)) { + OutputJsonKey(stream, kTestsuites, "random_seed", unit_test.random_seed(), + kIndent); + } + OutputJsonKey(stream, kTestsuites, "timestamp", + FormatEpochTimeInMillisAsRFC3339(unit_test.start_timestamp()), + kIndent); + OutputJsonKey(stream, kTestsuites, "time", + FormatTimeInMillisAsDuration(unit_test.elapsed_time()), kIndent, + false); + + *stream << TestPropertiesAsJson(unit_test.ad_hoc_test_result(), kIndent) + << ",\n"; + + OutputJsonKey(stream, kTestsuites, "name", "AllTests", kIndent); + *stream << kIndent << "\"" << kTestsuites << "\": [\n"; + + bool comma = false; + for (int i = 0; i < unit_test.total_test_case_count(); ++i) { + if (unit_test.GetTestCase(i)->reportable_test_count() > 0) { + if (comma) { + *stream << ",\n"; + } else { + comma = true; + } + PrintJsonTestCase(stream, *unit_test.GetTestCase(i)); + } + } + + *stream << "\n" << kIndent << "]\n" << "}\n"; +} + +void JsonUnitTestResultPrinter::PrintJsonTestList( + std::ostream* stream, const std::vector<TestCase*>& test_cases) { + const std::string kTestsuites = "testsuites"; + const std::string kIndent = Indent(2); + *stream << "{\n"; + int total_tests = 0; + for (size_t i = 0; i < test_cases.size(); ++i) { + total_tests += test_cases[i]->total_test_count(); + } + OutputJsonKey(stream, kTestsuites, "tests", total_tests, kIndent); + + OutputJsonKey(stream, kTestsuites, "name", "AllTests", kIndent); + *stream << kIndent << "\"" << kTestsuites << "\": [\n"; + + for (size_t i = 0; i < test_cases.size(); ++i) { + if (i != 0) { + *stream << ",\n"; + } + PrintJsonTestCase(stream, *test_cases[i]); + } + + *stream << "\n" + << kIndent << "]\n" + << "}\n"; +} +// Produces a string representing the test properties in a result as +// a JSON dictionary. +std::string JsonUnitTestResultPrinter::TestPropertiesAsJson( + const TestResult& result, const std::string& indent) { + Message attributes; + for (int i = 0; i < result.test_property_count(); ++i) { + const TestProperty& property = result.GetTestProperty(i); + attributes << ",\n" << indent << "\"" << property.key() << "\": " + << "\"" << EscapeJson(property.value()) << "\""; + } + return attributes.GetString(); +} + +// End JsonUnitTestResultPrinter + #if GTEST_CAN_STREAM_RESULTS_ // Checks if str contains '=', '&', '%' or '\n' characters. If yes, @@ -3758,8 +4242,8 @@ std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( // example, replaces "=" with "%3D". This algorithm is O(strlen(str)) // in both time and space -- important as the input str may contain an // arbitrarily long test failure message and stack trace. -string StreamingListener::UrlEncode(const char* str) { - string result; +std::string StreamingListener::UrlEncode(const char* str) { + std::string result; result.reserve(strlen(str) + 1); for (char ch = *str; ch != '\0'; ch = *++str) { switch (ch) { @@ -3821,47 +4305,82 @@ void StreamingListener::SocketWriter::MakeConnection() { // End of class Streaming Listener #endif // GTEST_CAN_STREAM_RESULTS__ -// Class ScopedTrace +// class OsStackTraceGetter -// Pushes the given source file location and message onto a per-thread -// trace stack maintained by Google Test. -ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) - GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { - TraceInfo trace; - trace.file = file; - trace.line = line; - trace.message = message.GetString(); +const char* const OsStackTraceGetterInterface::kElidedFramesMarker = + "... " GTEST_NAME_ " internal frames ..."; - UnitTest::GetInstance()->PushGTestTrace(trace); -} +std::string OsStackTraceGetter::CurrentStackTrace(int max_depth, int skip_count) + GTEST_LOCK_EXCLUDED_(mutex_) { +#if GTEST_HAS_ABSL + std::string result; -// Pops the info pushed by the c'tor. -ScopedTrace::~ScopedTrace() - GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { - UnitTest::GetInstance()->PopGTestTrace(); -} + if (max_depth <= 0) { + return result; + } + max_depth = std::min(max_depth, kMaxStackTraceDepth); -// class OsStackTraceGetter + std::vector<void*> raw_stack(max_depth); + // Skips the frames requested by the caller, plus this function. + const int raw_stack_size = + absl::GetStackTrace(&raw_stack[0], max_depth, skip_count + 1); -const char* const OsStackTraceGetterInterface::kElidedFramesMarker = - "... " GTEST_NAME_ " internal frames ..."; + void* caller_frame = nullptr; + { + MutexLock lock(&mutex_); + caller_frame = caller_frame_; + } + + for (int i = 0; i < raw_stack_size; ++i) { + if (raw_stack[i] == caller_frame && + !GTEST_FLAG(show_internal_stack_frames)) { + // Add a marker to the trace and stop adding frames. + absl::StrAppend(&result, kElidedFramesMarker, "\n"); + break; + } -string OsStackTraceGetter::CurrentStackTrace(int /*max_depth*/, - int /*skip_count*/) { + char tmp[1024]; + const char* symbol = "(unknown)"; + if (absl::Symbolize(raw_stack[i], tmp, sizeof(tmp))) { + symbol = tmp; + } + + char line[1024]; + snprintf(line, sizeof(line), " %p: %s\n", raw_stack[i], symbol); + result += line; + } + + return result; + +#else // !GTEST_HAS_ABSL + static_cast<void>(max_depth); + static_cast<void>(skip_count); return ""; +#endif // GTEST_HAS_ABSL } -void OsStackTraceGetter::UponLeavingGTest() {} +void OsStackTraceGetter::UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_) { +#if GTEST_HAS_ABSL + void* caller_frame = nullptr; + if (absl::GetStackTrace(&caller_frame, 1, 3) <= 0) { + caller_frame = nullptr; + } + + MutexLock lock(&mutex_); + caller_frame_ = caller_frame; +#endif // GTEST_HAS_ABSL +} // A helper class that creates the premature-exit file in its // constructor and deletes the file in its destructor. class ScopedPrematureExitFile { public: explicit ScopedPrematureExitFile(const char* premature_exit_filepath) - : premature_exit_filepath_(premature_exit_filepath) { + : premature_exit_filepath_(premature_exit_filepath ? + premature_exit_filepath : "") { // If a path to the premature-exit file is specified... - if (premature_exit_filepath != NULL && *premature_exit_filepath != '\0') { + if (!premature_exit_filepath_.empty()) { // create the file with a single "0" character in it. I/O // errors are ignored as there's nothing better we can do and we // don't want to fail the test because of this. @@ -3872,13 +4391,18 @@ class ScopedPrematureExitFile { } ~ScopedPrematureExitFile() { - if (premature_exit_filepath_ != NULL && *premature_exit_filepath_ != '\0') { - remove(premature_exit_filepath_); + if (!premature_exit_filepath_.empty()) { + int retval = remove(premature_exit_filepath_.c_str()); + if (retval) { + GTEST_LOG_(ERROR) << "Failed to remove premature exit filepath \"" + << premature_exit_filepath_ << "\" with error " + << retval; + } } } private: - const char* const premature_exit_filepath_; + const std::string premature_exit_filepath_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedPrematureExitFile); }; @@ -4148,6 +4672,11 @@ void UnitTest::AddTestPartResult( // when a failure happens and both the --gtest_break_on_failure and // the --gtest_catch_exceptions flags are specified. DebugBreak(); +#elif (!defined(__native_client__)) && \ + ((defined(__clang__) || defined(__GNUC__)) && \ + (defined(__x86_64__) || defined(__i386__))) + // with clang/gcc we can achieve the same effect on x86 by invoking int3 + asm("int3"); #else // Dereference NULL through a volatile pointer to prevent the compiler // from removing. We use this rather than abort() or __builtin_trap() for @@ -4215,7 +4744,7 @@ int UnitTest::Run() { // used for the duration of the program. impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions)); -#if GTEST_HAS_SEH +#if GTEST_OS_WINDOWS // Either the user wants Google Test to catch exceptions thrown by the // tests or this is executing in the context of death test child // process. In either case the user does not want to see pop-up dialogs @@ -4244,7 +4773,7 @@ int UnitTest::Run() { // VC++ doesn't define _set_abort_behavior() prior to the version 8.0. // Users of prior VC versions shall suffer the agony and pain of // clicking through the countless debug dialogs. - // TODO(vladl@google.com): find a way to suppress the abort dialog() in the + // FIXME: find a way to suppress the abort dialog() in the // debug mode when compiled with VC 7.1 or lower. if (!GTEST_FLAG(break_on_failure)) _set_abort_behavior( @@ -4252,7 +4781,7 @@ int UnitTest::Run() { _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. # endif } -#endif // GTEST_HAS_SEH +#endif // GTEST_OS_WINDOWS return internal::HandleExceptionsInMethodIfSupported( impl(), @@ -4285,7 +4814,6 @@ const TestInfo* UnitTest::current_test_info() const // Returns the random seed used at the start of the current test run. int UnitTest::random_seed() const { return impl_->random_seed(); } -#if GTEST_HAS_PARAM_TEST // Returns ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. internal::ParameterizedTestCaseRegistry& @@ -4293,7 +4821,6 @@ internal::ParameterizedTestCaseRegistry& GTEST_LOCK_EXCLUDED_(mutex_) { return impl_->parameterized_test_registry(); } -#endif // GTEST_HAS_PARAM_TEST // Creates an empty UnitTest. UnitTest::UnitTest() { @@ -4332,10 +4859,8 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent) &default_global_test_part_result_reporter_), per_thread_test_part_result_reporter_( &default_per_thread_test_part_result_reporter_), -#if GTEST_HAS_PARAM_TEST parameterized_test_registry_(), parameterized_tests_registered_(false), -#endif // GTEST_HAS_PARAM_TEST last_death_test_case_(-1), current_test_case_(NULL), current_test_info_(NULL), @@ -4402,10 +4927,12 @@ void UnitTestImpl::ConfigureXmlOutput() { if (output_format == "xml") { listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); + } else if (output_format == "json") { + listeners()->SetDefaultXmlGenerator(new JsonUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); } else if (output_format != "") { - printf("WARNING: unrecognized output format \"%s\" ignored.\n", - output_format.c_str()); - fflush(stdout); + GTEST_LOG_(WARNING) << "WARNING: unrecognized output format \"" + << output_format << "\" ignored."; } } @@ -4420,9 +4947,8 @@ void UnitTestImpl::ConfigureStreamingOutput() { listeners()->Append(new StreamingListener(target.substr(0, pos), target.substr(pos+1))); } else { - printf("WARNING: unrecognized streaming target \"%s\" ignored.\n", - target.c_str()); - fflush(stdout); + GTEST_LOG_(WARNING) << "unrecognized streaming target \"" << target + << "\" ignored."; } } } @@ -4461,6 +4987,13 @@ void UnitTestImpl::PostFlagParsingInit() { // Configures listeners for streaming test results to the specified server. ConfigureStreamingOutput(); #endif // GTEST_CAN_STREAM_RESULTS_ + +#if GTEST_HAS_ABSL + if (GTEST_FLAG(install_failure_signal_handler)) { + absl::FailureSignalHandlerOptions options; + absl::InstallFailureSignalHandler(options); + } +#endif // GTEST_HAS_ABSL } } @@ -4504,11 +5037,11 @@ TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc) { // Can we find a TestCase with the given name? - const std::vector<TestCase*>::const_iterator test_case = - std::find_if(test_cases_.begin(), test_cases_.end(), + const std::vector<TestCase*>::const_reverse_iterator test_case = + std::find_if(test_cases_.rbegin(), test_cases_.rend(), TestCaseNameIs(test_case_name)); - if (test_case != test_cases_.end()) + if (test_case != test_cases_.rend()) return *test_case; // No. Let's create one. @@ -4549,13 +5082,8 @@ static void TearDownEnvironment(Environment* env) { env->TearDown(); } // All other functions called from RunAllTests() may safely assume that // parameterized tests are ready to be counted and run. bool UnitTestImpl::RunAllTests() { - // Makes sure InitGoogleTest() was called. - if (!GTestIsInitialized()) { - printf("%s", - "\nThis test program did NOT call ::testing::InitGoogleTest " - "before calling RUN_ALL_TESTS(). Please fix it.\n"); - return false; - } + // True iff Google Test is initialized before RUN_ALL_TESTS() is called. + const bool gtest_is_initialized_before_run_all_tests = GTestIsInitialized(); // Do not run any test if the --help flag was specified. if (g_help_flag) @@ -4683,6 +5211,20 @@ bool UnitTestImpl::RunAllTests() { repeater->OnTestProgramEnd(*parent_); + if (!gtest_is_initialized_before_run_all_tests) { + ColoredPrintf( + COLOR_RED, + "\nIMPORTANT NOTICE - DO NOT IGNORE:\n" + "This test program did NOT call " GTEST_INIT_GOOGLE_TEST_NAME_ + "() before calling RUN_ALL_TESTS(). This is INVALID. Soon " GTEST_NAME_ + " will start to enforce the valid usage. " + "Please fix it ASAP, or IT WILL START TO FAIL.\n"); // NOLINT +#if GTEST_FOR_GOOGLE_ + ColoredPrintf(COLOR_RED, + "For more details, see http://wiki/Main/ValidGUnitMain.\n"); +#endif // GTEST_FOR_GOOGLE_ + } + return !failed; } @@ -4784,8 +5326,8 @@ bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { // each TestCase and TestInfo object. // If shard_tests == true, further filters tests based on sharding // variables in the environment - see -// http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide. -// Returns the number of tests that should run. +// https://github.com/google/googletest/blob/master/googletest/docs/advanced.md +// . Returns the number of tests that should run. int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? Int32FromEnvOrDie(kTestTotalShards, -1) : -1; @@ -4824,10 +5366,11 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && matches_filter; - const bool is_selected = is_runnable && - (shard_tests == IGNORE_SHARDING_PROTOCOL || - ShouldRunTestOnShard(total_shards, shard_index, - num_runnable_tests)); + const bool is_in_another_shard = + shard_tests != IGNORE_SHARDING_PROTOCOL && + !ShouldRunTestOnShard(total_shards, shard_index, num_runnable_tests); + test_info->is_in_another_shard_ = is_in_another_shard; + const bool is_selected = is_runnable && !is_in_another_shard; num_runnable_tests += is_runnable; num_selected_tests += is_selected; @@ -4897,6 +5440,23 @@ void UnitTestImpl::ListTestsMatchingFilter() { } } fflush(stdout); + const std::string& output_format = UnitTestOptions::GetOutputFormat(); + if (output_format == "xml" || output_format == "json") { + FILE* fileout = OpenFileForWriting( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str()); + std::stringstream stream; + if (output_format == "xml") { + XmlUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str()) + .PrintXmlTestsList(&stream, test_cases_); + } else if (output_format == "json") { + JsonUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str()) + .PrintJsonTestList(&stream, test_cases_); + } + fprintf(fileout, "%s", StringStreamToString(&stream).c_str()); + fclose(fileout); + } } // Sets the OS stack trace getter. @@ -4927,11 +5487,15 @@ OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { return os_stack_trace_getter_; } -// Returns the TestResult for the test that's currently running, or -// the TestResult for the ad hoc test if no test is running. +// Returns the most specific TestResult currently running. TestResult* UnitTestImpl::current_test_result() { - return current_test_info_ ? - &(current_test_info_->result_) : &ad_hoc_test_result_; + if (current_test_info_ != NULL) { + return ¤t_test_info_->result_; + } + if (current_test_case_ != NULL) { + return ¤t_test_case_->ad_hoc_test_result_; + } + return &ad_hoc_test_result_; } // Shuffles all test cases, and the tests within each test case, @@ -5012,9 +5576,8 @@ bool SkipPrefix(const char* prefix, const char** pstr) { // part can be omitted. // // Returns the value of the flag, or NULL if the parsing failed. -const char* ParseFlagValue(const char* str, - const char* flag, - bool def_optional) { +static const char* ParseFlagValue(const char* str, const char* flag, + bool def_optional) { // str and flag must not be NULL. if (str == NULL || flag == NULL) return NULL; @@ -5050,7 +5613,7 @@ const char* ParseFlagValue(const char* str, // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. -bool ParseBoolFlag(const char* str, const char* flag, bool* value) { +static bool ParseBoolFlag(const char* str, const char* flag, bool* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, true); @@ -5084,7 +5647,8 @@ bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. -bool ParseStringFlag(const char* str, const char* flag, std::string* value) { +template <typename String> +static bool ParseStringFlag(const char* str, const char* flag, String* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, false); @@ -5120,7 +5684,7 @@ static bool HasGoogleTestFlagPrefix(const char* str) { // @Y changes the color to yellow. // @D changes to the default terminal text color. // -// TODO(wan@google.com): Write tests for this once we add stdout +// FIXME: Write tests for this once we add stdout // capturing to Google Test. static void PrintColorEncoded(const char* str) { GTestColor color = COLOR_DEFAULT; // The current color. @@ -5186,24 +5750,25 @@ static const char kColorEncodedHelpMessage[] = " Enable/disable colored output. The default is @Gauto@D.\n" " -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" " Don't print the elapsed time of each test.\n" -" @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G" +" @G--" GTEST_FLAG_PREFIX_ "output=@Y(@Gjson@Y|@Gxml@Y)[@G:@YDIRECTORY_PATH@G" GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" -" Generate an XML report in the given directory or with the given file\n" -" name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" -#if GTEST_CAN_STREAM_RESULTS_ +" Generate a JSON or XML report in the given directory or with the given\n" +" file name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" +# if GTEST_CAN_STREAM_RESULTS_ " @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n" " Stream test results to the given server.\n" -#endif // GTEST_CAN_STREAM_RESULTS_ +# endif // GTEST_CAN_STREAM_RESULTS_ "\n" "Assertion Behavior:\n" -#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +# if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS " @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" " Set the default death test style.\n" -#endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +# endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS " @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" " Turn assertion failures into debugger break-points.\n" " @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" -" Turn assertion failures into C++ exceptions.\n" +" Turn assertion failures into C++ exceptions for use by an external\n" +" test framework.\n" " @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n" " Do not report exceptions as test failures. Instead, allow them\n" " to crash the program or throw a pop-up (on Windows).\n" @@ -5220,7 +5785,7 @@ static const char kColorEncodedHelpMessage[] = "(not one in your own code or tests), please report it to\n" "@G<" GTEST_DEV_EMAIL_ ">@D.\n"; -bool ParseGoogleTestFlag(const char* const arg) { +static bool ParseGoogleTestFlag(const char* const arg) { return ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, >EST_FLAG(also_run_disabled_tests)) || ParseBoolFlag(arg, kBreakOnFailureFlag, @@ -5238,6 +5803,7 @@ bool ParseGoogleTestFlag(const char* const arg) { ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || + ParseBoolFlag(arg, kPrintUTF8Flag, >EST_FLAG(print_utf8)) || ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || @@ -5250,14 +5816,11 @@ bool ParseGoogleTestFlag(const char* const arg) { } #if GTEST_USE_OWN_FLAGFILE_FLAG_ -void LoadFlagsFromFile(const std::string& path) { +static void LoadFlagsFromFile(const std::string& path) { FILE* flagfile = posix::FOpen(path.c_str(), "r"); if (!flagfile) { - fprintf(stderr, - "Unable to open file \"%s\"\n", - GTEST_FLAG(flagfile).c_str()); - fflush(stderr); - exit(EXIT_FAILURE); + GTEST_LOG_(FATAL) << "Unable to open file \"" << GTEST_FLAG(flagfile) + << "\""; } std::string contents(ReadEntireFile(flagfile)); posix::FClose(flagfile); @@ -5331,6 +5894,17 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { // other parts of Google Test. void ParseGoogleTestFlagsOnly(int* argc, char** argv) { ParseGoogleTestFlagsOnlyImpl(argc, argv); + + // Fix the value of *_NSGetArgc() on macOS, but iff + // *_NSGetArgv() == argv + // Only applicable to char** version of argv +#if GTEST_OS_MAC +#ifndef GTEST_OS_IOS + if (*_NSGetArgv() == argv) { + *_NSGetArgc() = *argc; + } +#endif +#endif } void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { ParseGoogleTestFlagsOnlyImpl(argc, argv); @@ -5352,6 +5926,10 @@ void InitGoogleTestImpl(int* argc, CharType** argv) { g_argvs.push_back(StreamableToString(argv[i])); } +#if GTEST_HAS_ABSL + absl::InitializeSymbolizer(g_argvs[0].c_str()); +#endif // GTEST_HAS_ABSL + ParseGoogleTestFlagsOnly(argc, argv); GetUnitTestImpl()->PostFlagParsingInit(); } @@ -5385,4 +5963,45 @@ void InitGoogleTest(int* argc, wchar_t** argv) { #endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) } +std::string TempDir() { +#if defined(GTEST_CUSTOM_TEMPDIR_FUNCTION_) + return GTEST_CUSTOM_TEMPDIR_FUNCTION_(); +#endif + +#if GTEST_OS_WINDOWS_MOBILE + return "\\temp\\"; +#elif GTEST_OS_WINDOWS + const char* temp_dir = internal::posix::GetEnv("TEMP"); + if (temp_dir == NULL || temp_dir[0] == '\0') + return "\\temp\\"; + else if (temp_dir[strlen(temp_dir) - 1] == '\\') + return temp_dir; + else + return std::string(temp_dir) + "\\"; +#elif GTEST_OS_LINUX_ANDROID + return "/sdcard/"; +#else + return "/tmp/"; +#endif // GTEST_OS_WINDOWS_MOBILE +} + +// Class ScopedTrace + +// Pushes the given source file location and message onto a per-thread +// trace stack maintained by Google Test. +void ScopedTrace::PushTrace(const char* file, int line, std::string message) { + internal::TraceInfo trace; + trace.file = file; + trace.line = line; + trace.message.swap(message); + + UnitTest::GetInstance()->PushGTestTrace(trace); +} + +// Pops the info pushed by the c'tor. +ScopedTrace::~ScopedTrace() + GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { + UnitTest::GetInstance()->PopGTestTrace(); +} + } // namespace testing diff --git a/test/googletest/src/gtest_main.cc b/test/googletest/src/gtest_main.cc index f3028225..2113f621 100644 --- a/test/googletest/src/gtest_main.cc +++ b/test/googletest/src/gtest_main.cc @@ -28,11 +28,10 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <stdio.h> - #include "gtest/gtest.h" GTEST_API_ int main(int argc, char **argv) { - printf("Running main() from gtest_main.cc\n"); + printf("Running main() from %s\n", __FILE__); testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 58638fa4..40a3dd06 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -2,32 +2,26 @@ option(USE_EXTERNAL_GTEST "Compile against external GTest" OFF) -if (USE_EXTERNAL_GTEST) +if(USE_EXTERNAL_GTEST) message(STATUS "Using external GTest") find_package(GTest 1.8.1 CONFIG REQUIRED) -else (USE_EXTERNAL_GTEST) +else() message(STATUS "Using internal GTest") -# FIXME: Deal with our old-school CMakeLists.txt behaving badly -set(_save_c_flags "${CMAKE_C_FLAGS}") -set(_save_cxx_flags "${CMAKE_CXX_FLAGS}") -string(REGEX REPLACE "\\-W[a-z\\-]+" "" CMAKE_C_FLAGS ${CMAKE_C_FLAGS}) -string(REGEX REPLACE "\\-W[a-z\\-]+" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) - # # Build Google Test # # Source https://github.com/google/googletest/blob/master/googletest/README.md # Download and unpack googletest at configure time configure_file( - ${CMAKE_SOURCE_DIR}/test/googletest/CMakeLists.txt.in - ${CMAKE_BINARY_DIR}/googletest-download/CMakeLists.txt) + ${CMAKE_SOURCE_DIR}/test/googletest/CMakeLists.txt.in + ${CMAKE_BINARY_DIR}/googletest-download/CMakeLists.txt) execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . RESULT_VARIABLE result - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download ) + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download) if(result) message(FATAL_ERROR "CMake step for googletest failed: ${result}") endif() @@ -43,31 +37,31 @@ set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) # Add googletest directly to our build. This defines # the gtest and gtest_main targets. option(INSTALL_GTEST "Enable installation of googletest" OFF) -add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src - ${CMAKE_BINARY_DIR}/googletest-build - EXCLUDE_FROM_ALL) - -# FIXME: Deal with our old-school CMakeLists.txt behaving badly -set(CMAKE_C_FLAGS "${_save_c_flags}") -set(CMAKE_CXX_FLAGS "${_save_cxx_flags}") -unset(_save_c_flags) -unset(_save_cxx_flags) +add_subdirectory( + ${CMAKE_BINARY_DIR}/googletest-src + ${CMAKE_BINARY_DIR}/googletest-build + EXCLUDE_FROM_ALL) # Provide the same target name as find_package(GTest) add_library(GTest::gtest ALIAS gtest) -endif(USE_EXTERNAL_GTEST) +endif() # USE_EXTERNAL_GTEST # # Build PROJ unit tests # if("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC" AND BUILD_LIBPROJ_SHARED) -add_definitions(-DPROJ_MSVC_DLL_IMPORT=1) + add_definitions(-DPROJ_MSVC_DLL_IMPORT=1) endif() include_directories(${CMAKE_SOURCE_DIR}/include) include_directories(${SQLITE3_INCLUDE_DIR}) +# Add the directory containing proj_config.h +include_directories(${CMAKE_BINARY_DIR}/src) + +# Apply to targets in the current directory and below +add_compile_options(${PROJ_CXX_WARN_FLAGS}) add_executable(proj_pj_transform_test main.cpp @@ -86,31 +80,31 @@ target_link_libraries(proj_errno_string_test add_test(NAME proj_errno_string_test COMMAND proj_errno_string_test) add_executable(proj_angular_io_test - main.cpp - proj_angular_io_test.cpp) + main.cpp + proj_angular_io_test.cpp) target_link_libraries(proj_angular_io_test - GTest::gtest - ${PROJ_LIBRARIES}) + GTest::gtest + ${PROJ_LIBRARIES}) add_test(NAME proj_angular_io_test COMMAND proj_angular_io_test) add_executable(proj_context_test - main.cpp - proj_context_test.cpp) + main.cpp + proj_context_test.cpp) target_link_libraries(proj_context_test - GTest::gtest - ${PROJ_LIBRARIES}) + GTest::gtest + ${PROJ_LIBRARIES}) add_test(NAME proj_context_test COMMAND proj_context_test) -if (MSVC AND BUILD_LIBPROJ_SHARED) -# ph_phi2_test not compatible of a .dll build +if(MSVC AND BUILD_LIBPROJ_SHARED) + # ph_phi2_test not compatible of a .dll build else() -add_executable(pj_phi2_test - main.cpp - pj_phi2_test.cpp) -target_link_libraries(pj_phi2_test - GTest::gtest - ${PROJ_LIBRARIES}) -add_test(NAME pj_phi2_test COMMAND pj_phi2_test) + add_executable(pj_phi2_test + main.cpp + pj_phi2_test.cpp) + target_link_libraries(pj_phi2_test + GTest::gtest + ${PROJ_LIBRARIES}) + add_test(NAME pj_phi2_test COMMAND pj_phi2_test) endif() add_executable(proj_test_cpp_api diff --git a/test/unit/gie_self_tests.cpp b/test/unit/gie_self_tests.cpp index ad637786..399f51e5 100644 --- a/test/unit/gie_self_tests.cpp +++ b/test/unit/gie_self_tests.cpp @@ -421,9 +421,11 @@ TEST(gie, info_functions) { /* check a few key characteristics of the Mercator projection */ EXPECT_NEAR(factors.angular_distortion, 0.0, 1e-7) << factors.angular_distortion; /* angular distortion should be 0 */ + + /* Meridian/parallel angle should be 90 deg */ EXPECT_NEAR(factors.meridian_parallel_angle, M_PI_2, 1e-7) - << factors.meridian_parallel_angle; /* Meridian/parallel angle should be - 90 deg */ + << factors.meridian_parallel_angle; + EXPECT_EQ(factors.meridian_convergence, 0.0); /* meridian convergence should be 0 */ @@ -701,13 +703,16 @@ TEST(gie, proj_create_crs_to_crs_PULKOVO42_ETRS89) { EXPECT_NEAR(c.xy.x, 44.999701238, 1e-9); EXPECT_NEAR(c.xy.y, 24.998474948, 1e-9); EXPECT_EQ(std::string(proj_pj_info(P).definition), - "proj=pipeline step proj=push v_3 step proj=axisswap order=2,1 " - "step proj=unitconvert xy_in=deg xy_out=rad step proj=cart " + "proj=pipeline step proj=axisswap order=2,1 " + "step proj=unitconvert xy_in=deg xy_out=rad " + "step proj=push v_3 " + "step proj=cart " "ellps=krass step proj=helmert x=2.3287 y=-147.0425 z=-92.0802 " "rx=0.3092483 ry=-0.32482185 rz=-0.49729934 s=5.68906266 " - "convention=coordinate_frame step inv proj=cart ellps=GRS80 step " - "proj=unitconvert xy_in=rad xy_out=deg step proj=axisswap " - "order=2,1 step proj=pop v_3"); + "convention=coordinate_frame step inv proj=cart ellps=GRS80 " + "step proj=pop v_3 " + "step proj=unitconvert xy_in=rad xy_out=deg step proj=axisswap " + "order=2,1"); c = proj_trans(P, PJ_INV, c); EXPECT_NEAR(c.xy.x, 45, 1e-8); @@ -730,12 +735,38 @@ TEST(gie, proj_create_crs_to_crs_PULKOVO42_ETRS89) { EXPECT_NEAR(c.xy.x, 51.999714150, 1e-9); EXPECT_NEAR(c.xy.y, 19.998187811, 1e-9); EXPECT_EQ(std::string(proj_pj_info(P).definition), - "proj=pipeline step proj=push v_3 step proj=axisswap order=2,1 " - "step proj=unitconvert xy_in=deg xy_out=rad step proj=cart " + "proj=pipeline step proj=axisswap order=2,1 " + "step proj=unitconvert xy_in=deg xy_out=rad " + "step proj=push v_3 " + "step proj=cart " "ellps=krass step proj=helmert x=33.4 y=-146.6 z=-76.3 rx=-0.359 " "ry=-0.053 rz=0.844 s=-0.84 convention=position_vector step inv " - "proj=cart ellps=GRS80 step proj=unitconvert xy_in=rad " - "xy_out=deg step proj=axisswap order=2,1 step proj=pop v_3"); + "proj=cart ellps=GRS80 step proj=pop v_3 " + "step proj=unitconvert xy_in=rad " + "xy_out=deg step proj=axisswap order=2,1"); + + proj_destroy(P); +} + +// --------------------------------------------------------------------------- + +TEST(gie, proj_create_crs_to_crs_outside_area_of_use) { + + // See https://github.com/OSGeo/proj.4/issues/1329 + auto P = proj_create_crs_to_crs(PJ_DEFAULT_CTX, "EPSG:4275", "EPSG:4807", + nullptr); + ASSERT_TRUE(P != nullptr); + PJ_COORD c; + + EXPECT_EQ(P->fwd, nullptr); + + // Test point outside area of use of both candidate coordinate operations + c.xyz.x = 58; // Lat in deg + c.xyz.y = 5; // Long in deg + c.xyz.z = 0; + c = proj_trans(P, PJ_FWD, c); + EXPECT_NEAR(c.xy.x, 64.44444444444444, 1e-9); // Lat in grad + EXPECT_NEAR(c.xy.y, 2.958634259259258, 1e-9); // Long in grad proj_destroy(P); } diff --git a/test/unit/proj_errno_string_test.cpp b/test/unit/proj_errno_string_test.cpp index dcdff5c4..a592b31f 100644 --- a/test/unit/proj_errno_string_test.cpp +++ b/test/unit/proj_errno_string_test.cpp @@ -29,6 +29,7 @@ #include <cstring> #include "proj.h" +#include "proj_config.h" #include "gtest_include.h" diff --git a/test/unit/test_c_api.cpp b/test/unit/test_c_api.cpp index 6205a9b8..b9ea0bd5 100644 --- a/test/unit/test_c_api.cpp +++ b/test/unit/test_c_api.cpp @@ -838,14 +838,16 @@ TEST_F(CApi, proj_create_from_database) { ASSERT_NE(info.definition, nullptr); EXPECT_EQ( info.definition, - std::string("proj=pipeline step proj=push v_3 step proj=axisswap " + std::string("proj=pipeline step proj=axisswap " "order=2,1 step proj=unitconvert xy_in=deg xy_out=rad " + "step proj=push v_3 " "step proj=cart ellps=bessel step proj=helmert " "x=601.705 y=84.263 z=485.227 rx=-4.7354 ry=-1.3145 " - "rz=-5.393 s=-2.3887 convention=coordinate_frame step " - "inv proj=cart ellps=GRS80 step proj=unitconvert " - "xy_in=rad xy_out=deg step proj=axisswap order=2,1 " - "step proj=pop v_3")); + "rz=-5.393 s=-2.3887 convention=coordinate_frame " + "step inv proj=cart ellps=GRS80 " + "step proj=pop v_3 " + "step proj=unitconvert xy_in=rad xy_out=deg " + "step proj=axisswap order=2,1")); EXPECT_EQ(info.accuracy, 1); } } @@ -1300,13 +1302,13 @@ TEST_F(CApi, proj_coordoperation_get_grid_used) { // --------------------------------------------------------------------------- -TEST_F(CApi, proj_coordoperation_is_instanciable) { +TEST_F(CApi, proj_coordoperation_is_instantiable) { auto op = proj_create_from_database(m_ctxt, "EPSG", "1671", PJ_CATEGORY_COORDINATE_OPERATION, true, nullptr); ASSERT_NE(op, nullptr); ObjectKeeper keeper(op); - EXPECT_EQ(proj_coordoperation_is_instanciable(m_ctxt, op), 1); + EXPECT_EQ(proj_coordoperation_is_instantiable(m_ctxt, op), 1); } // --------------------------------------------------------------------------- @@ -1343,6 +1345,7 @@ TEST_F(CApi, proj_create_operations) { auto op = proj_list_get(m_ctxt, res, 0); ASSERT_NE(op, nullptr); ObjectKeeper keeper_op(op); + EXPECT_FALSE(proj_coordoperation_has_ballpark_transformation(m_ctxt, op)); EXPECT_EQ(proj_get_name(op), std::string("NAD27 to NAD83 (3)")); } @@ -1399,8 +1402,9 @@ TEST_F(CApi, proj_create_operations_with_pivot) { ASSERT_NE(op, nullptr); ObjectKeeper keeper_op(op); - EXPECT_EQ(proj_get_name(op), - std::string("Null geographic offset from WGS 84 to JGD2011")); + EXPECT_EQ( + proj_get_name(op), + std::string("Ballpark geographic offset from WGS 84 to JGD2011")); } // Restrict pivot to Tokyo CRS @@ -1421,7 +1425,7 @@ TEST_F(CApi, proj_create_operations_with_pivot) { ASSERT_NE(res, nullptr); ObjListKeeper keeper_res(res); EXPECT_EQ(proj_list_get_count(res), 7); - auto op = proj_list_get(m_ctxt, res, 1); + auto op = proj_list_get(m_ctxt, res, 0); ASSERT_NE(op, nullptr); ObjectKeeper keeper_op(op); @@ -1451,7 +1455,7 @@ TEST_F(CApi, proj_create_operations_with_pivot) { ASSERT_NE(res, nullptr); ObjListKeeper keeper_res(res); // includes results from ESRI - EXPECT_EQ(proj_list_get_count(res), 5); + EXPECT_EQ(proj_list_get_count(res), 4); auto op = proj_list_get(m_ctxt, res, 0); ASSERT_NE(op, nullptr); ObjectKeeper keeper_op(op); @@ -1646,6 +1650,38 @@ TEST_F(CApi, proj_identify) { ObjListKeeper keeper_res(res); EXPECT_EQ(res, nullptr); } + { + auto obj2 = proj_create( + m_ctxt, "+proj=longlat +datum=WGS84 +no_defs +type=crs"); + ObjectKeeper keeper2(obj2); + ASSERT_NE(obj2, nullptr); + int *confidence = nullptr; + auto res = proj_identify(m_ctxt, obj2, nullptr, nullptr, &confidence); + ObjListKeeper keeper_res(res); + EXPECT_EQ(proj_list_get_count(res), 4); + proj_int_list_destroy(confidence); + } + { + auto obj2 = proj_create_from_database(m_ctxt, "IGNF", "ETRS89UTM28", + PJ_CATEGORY_CRS, false, nullptr); + ObjectKeeper keeper2(obj2); + ASSERT_NE(obj2, nullptr); + int *confidence = nullptr; + auto res = proj_identify(m_ctxt, obj2, "EPSG", nullptr, &confidence); + ObjListKeeper keeper_res(res); + EXPECT_EQ(proj_list_get_count(res), 1); + auto gotCRS = proj_list_get(m_ctxt, res, 0); + ASSERT_NE(gotCRS, nullptr); + ObjectKeeper keeper_gotCRS(gotCRS); + auto auth = proj_get_id_auth_name(gotCRS, 0); + ASSERT_TRUE(auth != nullptr); + EXPECT_EQ(auth, std::string("EPSG")); + auto code = proj_get_id_code(gotCRS, 0); + ASSERT_TRUE(code != nullptr); + EXPECT_EQ(code, std::string("25828")); + EXPECT_EQ(confidence[0], 70); + proj_int_list_destroy(confidence); + } } // --------------------------------------------------------------------------- @@ -3216,4 +3252,96 @@ TEST_F(CApi, proj_get_crs_info_list_from_database) { proj_crs_info_list_destroy(list); } } + +// --------------------------------------------------------------------------- + +TEST_F(CApi, proj_normalize_for_visualization) { + + { + auto P = proj_create(m_ctxt, "+proj=utm +zone=31 +ellps=WGS84"); + ObjectKeeper keeper_P(P); + ASSERT_NE(P, nullptr); + auto Pnormalized = proj_normalize_for_visualization(m_ctxt, P); + ObjectKeeper keeper_Pnormalized(Pnormalized); + EXPECT_EQ(Pnormalized, nullptr); + } + + auto P = proj_create_crs_to_crs(m_ctxt, "EPSG:4326", "EPSG:32631", nullptr); + ObjectKeeper keeper_P(P); + ASSERT_NE(P, nullptr); + auto Pnormalized = proj_normalize_for_visualization(m_ctxt, P); + ObjectKeeper keeper_Pnormalized(Pnormalized); + ASSERT_NE(Pnormalized, nullptr); + auto projstr = proj_as_proj_string(m_ctxt, Pnormalized, PJ_PROJ_5, nullptr); + ASSERT_NE(projstr, nullptr); + EXPECT_EQ(std::string(projstr), + "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad " + "+step +proj=utm +zone=31 +ellps=WGS84"); +} + +// --------------------------------------------------------------------------- + +TEST_F(CApi, proj_normalize_for_visualization_with_alternatives) { + + auto P = proj_create_crs_to_crs(m_ctxt, "EPSG:4326", "EPSG:3003", nullptr); + ObjectKeeper keeper_P(P); + ASSERT_NE(P, nullptr); + auto Pnormalized = proj_normalize_for_visualization(m_ctxt, P); + ObjectKeeper keeper_Pnormalized(Pnormalized); + ASSERT_NE(Pnormalized, nullptr); + + { + PJ_COORD c; + // Approximately Roma + c.lpz.lam = 12.5; + c.lpz.phi = 42; + c.lpz.z = 0; + c = proj_trans(Pnormalized, PJ_FWD, c); + EXPECT_NEAR(c.xy.x, 1789912.46264783037, 1e-8); + EXPECT_NEAR(c.xy.y, 4655716.25402576849, 1e-8); + auto projstr = proj_pj_info(Pnormalized).definition; + ASSERT_NE(projstr, nullptr); + EXPECT_EQ(std::string(projstr), + "proj=pipeline step proj=unitconvert xy_in=deg xy_out=rad " + "step proj=push v_3 step proj=cart ellps=WGS84 " + "step inv proj=helmert x=-104.1 y=-49.1 z=-9.9 rx=0.971 " + "ry=-2.917 rz=0.714 s=-11.68 convention=position_vector " + "step inv proj=cart ellps=intl step proj=pop v_3 " + "step proj=tmerc lat_0=0 lon_0=9 k=0.9996 x_0=1500000 " + "y_0=0 ellps=intl"); + } + + { + PJ_COORD c; + // Approximately Roma + c.xyz.x = 1789912.46264783037; + c.xyz.y = 4655716.25402576849; + c.xyz.z = 0; + c = proj_trans(Pnormalized, PJ_INV, c); + EXPECT_NEAR(c.lp.lam, 12.5, 1e-8); + EXPECT_NEAR(c.lp.phi, 42, 1e-8); + } +} + +// --------------------------------------------------------------------------- + +TEST_F(CApi, proj_normalize_for_visualization_with_alternatives_reverse) { + + auto P = proj_create_crs_to_crs(m_ctxt, "EPSG:3003", "EPSG:4326", nullptr); + ObjectKeeper keeper_P(P); + ASSERT_NE(P, nullptr); + auto Pnormalized = proj_normalize_for_visualization(m_ctxt, P); + ObjectKeeper keeper_Pnormalized(Pnormalized); + ASSERT_NE(Pnormalized, nullptr); + + PJ_COORD c; + // Approximately Roma + c.xyz.x = 1789912.46264783037; + c.xyz.y = 4655716.25402576849; + c.xyz.z = 0; + c = proj_trans(Pnormalized, PJ_FWD, c); + EXPECT_NEAR(c.lp.lam, 12.5, 1e-8); + EXPECT_NEAR(c.lp.phi, 42, 1e-8); +} + } // namespace diff --git a/test/unit/test_crs.cpp b/test/unit/test_crs.cpp index 4953529c..0f0304b1 100644 --- a/test/unit/test_crs.cpp +++ b/test/unit/test_crs.cpp @@ -148,32 +148,72 @@ TEST(crs, GeographicCRS_datum_ensemble) { std::vector<DatumNNPtr>{GeodeticReferenceFrame::EPSG_6326, GeodeticReferenceFrame::EPSG_6326}, PositionalAccuracy::create("100")); - auto crs = GeographicCRS::create( - PropertyMap().set(IdentifiedObject::NAME_KEY, "unnamed"), nullptr, - ensemble_vdatum, - EllipsoidalCS::createLatitudeLongitude(UnitOfMeasure::DEGREE)); - WKTFormatterNNPtr f( - WKTFormatter::create(WKTFormatter::Convention::WKT2_2018)); - f->simulCurNodeHasId(); - crs->exportToWKT(f.get()); - auto expected = "GEOGCRS[\"unnamed\",\n" - " ENSEMBLE[\"unnamed\",\n" - " MEMBER[\"World Geodetic System 1984\"],\n" - " MEMBER[\"World Geodetic System 1984\"],\n" - " ELLIPSOID[\"WGS 84\",6378137,298.257223563,\n" - " LENGTHUNIT[\"metre\",1]],\n" - " ENSEMBLEACCURACY[100]],\n" - " PRIMEM[\"Greenwich\",0,\n" - " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" - " CS[ellipsoidal,2],\n" - " AXIS[\"latitude\",north,\n" - " ORDER[1],\n" - " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" - " AXIS[\"longitude\",east,\n" - " ORDER[2],\n" - " ANGLEUNIT[\"degree\",0.0174532925199433]]]"; + { + auto crs = GeographicCRS::create( + PropertyMap() + .set(IdentifiedObject::NAME_KEY, "unnamed") + .set(Identifier::CODESPACE_KEY, "MY_CODESPACE") + .set(Identifier::CODE_KEY, "MY_ID"), + nullptr, ensemble_vdatum, + EllipsoidalCS::createLatitudeLongitude(UnitOfMeasure::DEGREE)); + WKTFormatterNNPtr f( + WKTFormatter::create(WKTFormatter::Convention::WKT2_2018)); + crs->exportToWKT(f.get()); + auto expected = + "GEOGCRS[\"unnamed\",\n" + " ENSEMBLE[\"unnamed\",\n" + " MEMBER[\"World Geodetic System 1984\"],\n" + " MEMBER[\"World Geodetic System 1984\"],\n" + " ELLIPSOID[\"WGS 84\",6378137,298.257223563,\n" + " LENGTHUNIT[\"metre\",1]],\n" + " ENSEMBLEACCURACY[100]],\n" + " PRIMEM[\"Greenwich\",0,\n" + " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" + " CS[ellipsoidal,2],\n" + " AXIS[\"latitude\",north,\n" + " ORDER[1],\n" + " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" + " AXIS[\"longitude\",east,\n" + " ORDER[2],\n" + " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" + " ID[\"MY_CODESPACE\",\"MY_ID\"]]"; - EXPECT_EQ(f->toString(), expected); + EXPECT_EQ(f->toString(), expected); + } + + { + auto crs = GeographicCRS::create( + PropertyMap().set(IdentifiedObject::NAME_KEY, "unnamed"), nullptr, + ensemble_vdatum, + EllipsoidalCS::createLatitudeLongitude(UnitOfMeasure::DEGREE)); + WKTFormatterNNPtr f( + WKTFormatter::create(WKTFormatter::Convention::WKT2_2018)); + crs->exportToWKT(f.get()); + auto expected = "GEOGCRS[\"unnamed\",\n" + " ENSEMBLE[\"unnamed\",\n" + " MEMBER[\"World Geodetic System 1984\",\n" + " ID[\"EPSG\",6326]],\n" + " MEMBER[\"World Geodetic System 1984\",\n" + " ID[\"EPSG\",6326]],\n" + " ELLIPSOID[\"WGS 84\",6378137,298.257223563,\n" + " LENGTHUNIT[\"metre\",1],\n" + " ID[\"EPSG\",7030]],\n" + " ENSEMBLEACCURACY[100]],\n" + " PRIMEM[\"Greenwich\",0,\n" + " ANGLEUNIT[\"degree\",0.0174532925199433],\n" + " ID[\"EPSG\",8901]],\n" + " CS[ellipsoidal,2],\n" + " AXIS[\"latitude\",north,\n" + " ORDER[1],\n" + " ANGLEUNIT[\"degree\",0.0174532925199433,\n" + " ID[\"EPSG\",9122]]],\n" + " AXIS[\"longitude\",east,\n" + " ORDER[2],\n" + " ANGLEUNIT[\"degree\",0.0174532925199433,\n" + " ID[\"EPSG\",9122]]]]"; + + EXPECT_EQ(f->toString(), expected); + } } // --------------------------------------------------------------------------- @@ -1458,6 +1498,19 @@ TEST(crs, geodeticcrs_identify_db) { ->identify(factory); ASSERT_EQ(res.size(), 0U); } + { + // Test identification from PROJ string + auto obj = PROJStringParser().createFromPROJString( + "+proj=longlat +datum=WGS84 +type=crs"); + auto crs = nn_dynamic_pointer_cast<GeographicCRS>(obj); + ASSERT_TRUE(crs != nullptr); + auto res = crs->identify(factory); + ASSERT_EQ(res.size(), 1U); + ASSERT_TRUE(!res.front().first->identifiers().empty()); + EXPECT_EQ(*res.front().first->identifiers()[0]->codeSpace(), "EPSG"); + EXPECT_EQ(res.front().first->identifiers()[0]->code(), "4326"); + EXPECT_EQ(res.front().second, 70); + } } // --------------------------------------------------------------------------- @@ -1561,6 +1614,52 @@ TEST(crs, projectedCRS_as_WKT2) { // --------------------------------------------------------------------------- +TEST(crs, projectedCRS_as_WKT2_2018) { + auto crs = createProjected(); + + auto expected = + "PROJCRS[\"WGS 84 / UTM zone 31N\",\n" + " BASEGEOGCRS[\"WGS 84\",\n" + " DATUM[\"World Geodetic System 1984\",\n" + " ELLIPSOID[\"WGS 84\",6378137,298.257223563,\n" + " LENGTHUNIT[\"metre\",1]]],\n" + " PRIMEM[\"Greenwich\",0,\n" + " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" + " ID[\"EPSG\",4326]],\n" + " CONVERSION[\"UTM zone 31N\",\n" + " METHOD[\"Transverse Mercator\",\n" + " ID[\"EPSG\",9807]],\n" + " PARAMETER[\"Latitude of natural origin\",0,\n" + " ANGLEUNIT[\"degree\",0.0174532925199433],\n" + " ID[\"EPSG\",8801]],\n" + " PARAMETER[\"Longitude of natural origin\",3,\n" + " ANGLEUNIT[\"degree\",0.0174532925199433],\n" + " ID[\"EPSG\",8802]],\n" + " PARAMETER[\"Scale factor at natural origin\",0.9996,\n" + " SCALEUNIT[\"unity\",1],\n" + " ID[\"EPSG\",8805]],\n" + " PARAMETER[\"False easting\",500000,\n" + " LENGTHUNIT[\"metre\",1],\n" + " ID[\"EPSG\",8806]],\n" + " PARAMETER[\"False northing\",0,\n" + " LENGTHUNIT[\"metre\",1],\n" + " ID[\"EPSG\",8807]]],\n" + " CS[Cartesian,2],\n" + " AXIS[\"(E)\",east,\n" + " ORDER[1],\n" + " LENGTHUNIT[\"metre\",1]],\n" + " AXIS[\"(N)\",north,\n" + " ORDER[2],\n" + " LENGTHUNIT[\"metre\",1]],\n" + " ID[\"EPSG\",32631]]"; + + EXPECT_EQ( + crs->exportToWKT( + WKTFormatter::create(WKTFormatter::Convention::WKT2_2018).get()), + expected); +} +// --------------------------------------------------------------------------- + TEST(crs, projectedCRS_as_WKT2_simplified) { auto crs = createProjected(); @@ -1885,13 +1984,35 @@ TEST(crs, projectedCRS_identify_no_db) { TEST(crs, projectedCRS_identify_db) { auto dbContext = DatabaseContext::create(); auto factoryEPSG = AuthorityFactory::create(dbContext, "EPSG"); + auto factoryIGNF = AuthorityFactory::create(dbContext, "IGNF"); + auto factoryAnonymous = AuthorityFactory::create(dbContext, std::string()); { // Identify by existing code - auto res = - factoryEPSG->createProjectedCRS("2172")->identify(factoryEPSG); - ASSERT_EQ(res.size(), 1U); - EXPECT_EQ(res.front().first->getEPSGCode(), 2172); - EXPECT_EQ(res.front().second, 100); + auto crs = factoryEPSG->createProjectedCRS("2172"); + { + auto res = crs->identify(factoryEPSG); + ASSERT_EQ(res.size(), 1U); + EXPECT_EQ(res.front().first->getEPSGCode(), 2172); + EXPECT_EQ(res.front().second, 100); + } + { + auto res = crs->identify(factoryAnonymous); + ASSERT_EQ(res.size(), 1U); + } + { + auto res = crs->identify(factoryIGNF); + ASSERT_EQ(res.size(), 0U); + } + } + { + // Identify by existing code + auto crs = factoryIGNF->createProjectedCRS("ETRS89UTM28"); + { + auto res = crs->identify(factoryEPSG); + ASSERT_EQ(res.size(), 1U); + EXPECT_EQ(res.front().first->getEPSGCode(), 25828); + EXPECT_EQ(res.front().second, 70); + } } { // Non-existing code @@ -4522,7 +4643,8 @@ TEST(crs, DerivedVerticalCRS_WKT2) { auto expected = "VERTCRS[\"Derived vertCRS\",\n" " BASEVERTCRS[\"ODN height\",\n" - " VDATUM[\"Ordnance Datum Newlyn\"]],\n" + " VDATUM[\"Ordnance Datum Newlyn\",\n" + " ID[\"EPSG\",5101]]],\n" " DERIVINGCONVERSION[\"unnamed\",\n" " METHOD[\"PROJ unimplemented\"]],\n" " CS[vertical,1],\n" diff --git a/test/unit/test_datum.cpp b/test/unit/test_datum.cpp index 23c14f67..fa53ff85 100644 --- a/test/unit/test_datum.cpp +++ b/test/unit/test_datum.cpp @@ -175,7 +175,7 @@ TEST(datum, prime_meridian_to_PROJString) { EXPECT_EQ(PrimeMeridian::GREENWICH->exportToPROJString( PROJStringFormatter::create().get()), - ""); + "+proj=noop"); EXPECT_EQ(PrimeMeridian::PARIS->exportToPROJString( PROJStringFormatter::create().get()), @@ -195,7 +195,7 @@ TEST(datum, prime_meridian_to_PROJString) { PropertyMap().set(IdentifiedObject::NAME_KEY, "Origin meridian"), Angle(0)) ->exportToPROJString(PROJStringFormatter::create().get()), - ""); + "+proj=noop"); EXPECT_TRUE(PrimeMeridian::GREENWICH->isEquivalentTo( PrimeMeridian::GREENWICH.get())); diff --git a/test/unit/test_factory.cpp b/test/unit/test_factory.cpp index 80de017f..91024d62 100644 --- a/test/unit/test_factory.cpp +++ b/test/unit/test_factory.cpp @@ -150,7 +150,8 @@ TEST(factory, AuthorityFactory_createPrimeMeridian) { EXPECT_THROW(factory->createPrimeMeridian("-1"), NoSuchAuthorityCodeException); EXPECT_TRUE(nn_dynamic_pointer_cast<PrimeMeridian>( - factory->createObject("8903")) != nullptr); + AuthorityFactory::create(DatabaseContext::create(), "ESRI") + ->createObject("108900")) != nullptr); auto pm = factory->createPrimeMeridian("8903"); ASSERT_EQ(pm->identifiers().size(), 1U); EXPECT_EQ(pm->identifiers()[0]->code(), "8903"); @@ -660,13 +661,13 @@ TEST(factory, AuthorityFactory_createCoordinateOperation_helmert_3) { NoSuchAuthorityCodeException); auto op = factory->createCoordinateOperation("1113", false); EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), - "+proj=pipeline +step +proj=push +v_3 +step +proj=axisswap " - "+order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step " - "+inv +proj=longlat +a=6378249.145 +rf=293.4663077 +step " - "+proj=cart +a=6378249.145 +rf=293.4663077 +step +proj=helmert " - "+x=-143 +y=-90 +z=-294 +step +inv +proj=cart +ellps=WGS84 +step " - "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap " - "+order=2,1 +step +proj=pop +v_3"); + "+proj=pipeline +step +proj=axisswap +order=2,1 +step " + "+proj=unitconvert +xy_in=deg +xy_out=rad +step +inv " + "+proj=longlat +a=6378249.145 +rf=293.4663077 +step +proj=push " + "+v_3 +step +proj=cart +a=6378249.145 +rf=293.4663077 +step " + "+proj=helmert +x=-143 +y=-90 +z=-294 +step +inv +proj=cart " + "+ellps=WGS84 +step +proj=pop +v_3 +step +proj=unitconvert " + "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1"); } // --------------------------------------------------------------------------- @@ -675,13 +676,13 @@ TEST(factory, AuthorityFactory_createCoordinateOperation_helmert_7_CF) { auto factory = AuthorityFactory::create(DatabaseContext::create(), "EPSG"); auto op = factory->createCoordinateOperation("7676", false); EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), - "+proj=pipeline +step +proj=push +v_3 +step +proj=axisswap " - "+order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step " - "+proj=cart +ellps=bessel +step +proj=helmert +x=577.88891 " + "+proj=pipeline +step +proj=axisswap +order=2,1 +step " + "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 " + "+step +proj=cart +ellps=bessel +step +proj=helmert +x=577.88891 " "+y=165.22205 +z=391.18289 +rx=-4.9145 +ry=0.94729 +rz=13.05098 " "+s=7.78664 +convention=coordinate_frame +step +inv +proj=cart " - "+ellps=WGS84 +step +proj=unitconvert +xy_in=rad +xy_out=deg " - "+step +proj=axisswap +order=2,1 +step +proj=pop +v_3"); + "+ellps=WGS84 +step +proj=pop +v_3 +step +proj=unitconvert " + "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1"); } // --------------------------------------------------------------------------- @@ -717,6 +718,7 @@ TEST(factory, AuthorityFactory_createCoordinateOperation_helmert_15_CF) { auto op = factory->createCoordinateOperation("6276", false); auto expected = "COORDINATEOPERATION[\"ITRF2008 to GDA94 (1)\",\n" + " VERSION[\"GA-Aus 2010\"],\n" " SOURCECRS[\n" " GEODCRS[\"ITRF2008\",\n" " DATUM[\"International Terrestrial Reference Frame " @@ -734,7 +736,8 @@ TEST(factory, AuthorityFactory_createCoordinateOperation_helmert_15_CF) { " LENGTHUNIT[\"metre\",1]],\n" " AXIS[\"(Z)\",geocentricZ,\n" " ORDER[3],\n" - " LENGTHUNIT[\"metre\",1]]]],\n" + " LENGTHUNIT[\"metre\",1]],\n" + " ID[\"EPSG\",5332]]],\n" " TARGETCRS[\n" " GEODCRS[\"GDA94\",\n" " DATUM[\"Geocentric Datum of Australia 1994\",\n" @@ -751,7 +754,8 @@ TEST(factory, AuthorityFactory_createCoordinateOperation_helmert_15_CF) { " LENGTHUNIT[\"metre\",1]],\n" " AXIS[\"(Z)\",geocentricZ,\n" " ORDER[3],\n" - " LENGTHUNIT[\"metre\",1]]]],\n" + " LENGTHUNIT[\"metre\",1]],\n" + " ID[\"EPSG\",4938]]],\n" " METHOD[\"Time-dependent Coordinate Frame rotation (geocen)\",\n" " ID[\"EPSG\",1056]],\n" " PARAMETER[\"X-axis translation\",-84.68,\n" @@ -852,15 +856,15 @@ TEST(factory, EXPECT_TRUE(so->validateParameters().empty()); EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), - "+proj=pipeline +step +proj=push +v_3 +step +proj=axisswap " - "+order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step " - "+proj=cart +ellps=bessel +step +proj=molobadekas +x=593.032 " - "+y=26 +z=478.741 +rx=0.409394387439237 +ry=-0.359705195614311 " - "+rz=1.86849100035057 +s=4.0772 +px=3903453.148 +py=368135.313 " - "+pz=5012970.306 +convention=coordinate_frame +step +inv " - "+proj=cart +ellps=GRS80 +step +proj=unitconvert +xy_in=rad " - "+xy_out=deg +step +proj=axisswap +order=2,1 +step +proj=pop " - "+v_3"); + "+proj=pipeline +step +proj=axisswap +order=2,1 +step " + "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 " + "+step +proj=cart +ellps=bessel +step +proj=molobadekas " + "+x=593.032 +y=26 +z=478.741 +rx=0.409394387439237 " + "+ry=-0.359705195614311 +rz=1.86849100035057 +s=4.0772 " + "+px=3903453.148 +py=368135.313 +pz=5012970.306 " + "+convention=coordinate_frame +step +inv +proj=cart +ellps=GRS80 " + "+step +proj=pop +v_3 +step +proj=unitconvert +xy_in=rad " + "+xy_out=deg +step +proj=axisswap +order=2,1"); } // --------------------------------------------------------------------------- @@ -872,6 +876,7 @@ TEST( auto op = factory->createCoordinateOperation("1295", false); auto expected = "COORDINATEOPERATION[\"RGNC91-93 to NEA74 Noumea (4)\",\n" + " VERSION[\"ESRI-Ncl 0.05m\"],\n" " SOURCECRS[\n" " GEOGCRS[\"RGNC91-93\",\n" " DATUM[\"Reseau Geodesique de Nouvelle Caledonie 91-93\",\n" @@ -885,7 +890,8 @@ TEST( " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" " AXIS[\"geodetic longitude (Lon)\",east,\n" " ORDER[2],\n" - " ANGLEUNIT[\"degree\",0.0174532925199433]]]],\n" + " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" + " ID[\"EPSG\",4749]]],\n" " TARGETCRS[\n" " GEOGCRS[\"NEA74 Noumea\",\n" " DATUM[\"NEA74 Noumea\",\n" @@ -899,7 +905,8 @@ TEST( " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" " AXIS[\"geodetic longitude (Lon)\",east,\n" " ORDER[2],\n" - " ANGLEUNIT[\"degree\",0.0174532925199433]]]],\n" + " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" + " ID[\"EPSG\",4644]]],\n" " METHOD[\"NTv2\",\n" " ID[\"EPSG\",9615]],\n" " PARAMETERFILE[\"Latitude and longitude difference " @@ -939,6 +946,7 @@ TEST(factory, AuthorityFactory_createCoordinateOperation_other_transformation) { auto op = factory->createCoordinateOperation("1884", false); auto expected = "COORDINATEOPERATION[\"S-JTSK (Ferro) to S-JTSK (1)\",\n" + " VERSION[\"EPSG-Cze\"],\n" " SOURCECRS[\n" " GEOGCRS[\"S-JTSK (Ferro)\",\n" " DATUM[\"System of the Unified Trigonometrical Cadastral " @@ -953,7 +961,8 @@ TEST(factory, AuthorityFactory_createCoordinateOperation_other_transformation) { " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" " AXIS[\"geodetic longitude (Lon)\",east,\n" " ORDER[2],\n" - " ANGLEUNIT[\"degree\",0.0174532925199433]]]],\n" + " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" + " ID[\"EPSG\",4818]]],\n" " TARGETCRS[\n" " GEOGCRS[\"S-JTSK\",\n" " DATUM[\"System of the Unified Trigonometrical Cadastral " @@ -968,7 +977,8 @@ TEST(factory, AuthorityFactory_createCoordinateOperation_other_transformation) { " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" " AXIS[\"geodetic longitude (Lon)\",east,\n" " ORDER[2],\n" - " ANGLEUNIT[\"degree\",0.0174532925199433]]]],\n" + " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" + " ID[\"EPSG\",4156]]],\n" " METHOD[\"Longitude rotation\",\n" " ID[\"EPSG\",9601]],\n" " PARAMETER[\"Longitude offset\",-17.6666666666667,\n" @@ -1465,7 +1475,7 @@ class FactoryWithTmpDatabase : public ::testing::Test { "'EPSG','4326','EPSG','1262',44.0,-143." "0,-90.0,-294.0,'EPSG','9001',NULL,NULL,NULL,NULL,NULL,NULL," "NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL," - "NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);")) + "NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);")) << last_error(); ASSERT_TRUE(execute( @@ -1474,7 +1484,8 @@ class FactoryWithTmpDatabase : public ::testing::Test { "'EPSG','9615'" ",'NTv2','EPSG','4326','EPSG','4326','EPSG','1262',1.0,'EPSG','" "8656','Latitude and longitude difference " - "file','nzgd2kgrid0005.gsb',NULL,NULL,NULL,NULL,NULL,NULL,0);")) + "file','nzgd2kgrid0005.gsb',NULL,NULL,NULL,NULL,NULL,NULL,NULL," + "0);")) << last_error(); ASSERT_TRUE(execute( @@ -1491,7 +1502,7 @@ class FactoryWithTmpDatabase : public ::testing::Test { "offset',-17.4,'EPSG','9110',NULL,NULL,NULL,NULL,NULL,NULL," "NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL," "NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL," - "NULL,NULL,NULL,NULL,NULL,NULL,0);")) + "NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);")) << last_error(); ASSERT_TRUE(execute( @@ -1499,7 +1510,7 @@ class FactoryWithTmpDatabase : public ::testing::Test { "VALUES('EPSG','DUMMY_CONCATENATED','name',NULL,NULL," "'EPSG','4326','EPSG'" ",'4326','EPSG','1262',NULL,'EPSG','DUMMY_OTHER_TRANSFORMATION'" - ",'EPSG','DUMMY_OTHER_TRANSFORMATION',NULL,NULL,0);")) + ",'EPSG','DUMMY_OTHER_TRANSFORMATION',NULL,NULL,NULL,0);")) << last_error(); } @@ -1507,12 +1518,20 @@ class FactoryWithTmpDatabase : public ::testing::Test { const auto vals = std::vector<std::string>{"SOURCE", "TARGET", "PIVOT"}; for (const auto &val : vals) { + ASSERT_TRUE( + execute("INSERT INTO geodetic_datum " + "VALUES('FOO','" + + val + "','" + val + + "','',NULL," + "'EPSG','7030','EPSG','8901','EPSG','1262',0);")) + << last_error(); ASSERT_TRUE(execute("INSERT INTO geodetic_crs " "VALUES('NS_" + val + "','" + val + "','" + val + "',NULL,NULL,'geographic 2D','EPSG','6422'," - "'EPSG','6326'," - "'EPSG','1262',NULL,0);")) + "'FOO','" + + val + "'," + "'EPSG','1262',NULL,0);")) << last_error(); } } @@ -1530,7 +1549,7 @@ class FactoryWithTmpDatabase : public ::testing::Test { "','EPSG'" ",'1262',1.0,0,0,0,'EPSG','9001',NULL,NULL,NULL,NULL,NULL,NULL," "NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL," - "NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);")) + "NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);")) << last_error(); } @@ -1838,7 +1857,7 @@ TEST_F(FactoryWithTmpDatabase, "'EPSG','9615'" ",'NTv2','EPSG','4326','OTHER','OTHER_4326','EPSG','1262',1.0,'EPSG','" "8656','Latitude and longitude difference " - "file','nzgd2kgrid0005.gsb',NULL,NULL,NULL,NULL,NULL,NULL,0);")) + "file','nzgd2kgrid0005.gsb',NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);")) << last_error(); { auto res = factoryGeneral->createFromCoordinateReferenceSystemCodes( @@ -1870,7 +1889,7 @@ TEST_F(FactoryWithTmpDatabase, "'EPSG','9615'" ",'NTv2','EPSG','4326','EPSG','4326','EPSG','1262',10.0,'EPSG','" "8656','Latitude and longitude difference " - "file','nzgd2kgrid0005.gsb',NULL,NULL,NULL,NULL,NULL,NULL,0);")) + "file','nzgd2kgrid0005.gsb',NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);")) << last_error(); ASSERT_TRUE( @@ -1879,7 +1898,8 @@ TEST_F(FactoryWithTmpDatabase, "TRANSFORMATION_1M_SMALL_EXTENT',NULL,NULL,'EPSG','9615'" ",'NTv2','EPSG','4326','EPSG','4326','EPSG','2060',1.0,'EPSG','" "8656','Latitude and longitude difference " - "file','nzgd2kgrid0005.gsb',NULL,NULL,NULL,NULL,NULL,NULL,0);")) + "file','nzgd2kgrid0005.gsb',NULL,NULL,NULL,NULL,NULL,NULL," + "NULL,0);")) << last_error(); ASSERT_TRUE(execute( @@ -1888,7 +1908,7 @@ TEST_F(FactoryWithTmpDatabase, "'EPSG','9615'" ",'NTv2','EPSG','4326','EPSG','4326','EPSG','1262',1.0,'EPSG','" "8656','Latitude and longitude difference " - "file','nzgd2kgrid0005.gsb',NULL,NULL,NULL,NULL,NULL,NULL,0);")) + "file','nzgd2kgrid0005.gsb',NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);")) << last_error(); ASSERT_TRUE( @@ -1897,7 +1917,8 @@ TEST_F(FactoryWithTmpDatabase, "TRANSFORMATION_0.5M_DEPRECATED',NULL,NULL,'EPSG','9615'" ",'NTv2','EPSG','4326','EPSG','4326','EPSG','1262',1.0,'EPSG','" "8656','Latitude and longitude difference " - "file','nzgd2kgrid0005.gsb',NULL,NULL,NULL,NULL,NULL,NULL,1);")) + "file','nzgd2kgrid0005.gsb',NULL,NULL,NULL,NULL,NULL,NULL," + "NULL,1);")) << last_error(); auto factoryOTHER = @@ -2000,7 +2021,7 @@ TEST_F(FactoryWithTmpDatabase, AuthorityFactory_proj_based_transformation) { "NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL," "NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL," "NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL," - "NULL,NULL,NULL,NULL,NULL,NULL,0);")) + "NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);")) << last_error(); auto factoryOTHER = @@ -2061,7 +2082,7 @@ TEST_F(FactoryWithTmpDatabase, AuthorityFactory_wkt_based_transformation) { "NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL," "NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL," "NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL," - "NULL,NULL,NULL,NULL,NULL,NULL,0);")) + "NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);")) << last_error(); auto factoryOTHER = @@ -2071,12 +2092,12 @@ TEST_F(FactoryWithTmpDatabase, AuthorityFactory_wkt_based_transformation) { ASSERT_EQ(res.size(), 1U); EXPECT_EQ(res[0]->nameStr(), "My WKT string based op"); EXPECT_EQ(res[0]->exportToPROJString(PROJStringFormatter::create().get()), - "+proj=pipeline +step +proj=push +v_3 +step +proj=axisswap " - "+order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step " - "+proj=cart +ellps=WGS84 +step +proj=helmert +x=1 +y=2 +z=3 " - "+step +inv +proj=cart +ellps=WGS84 +step +proj=unitconvert " - "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1 +step " - "+proj=pop +v_3"); + "+proj=pipeline +step +proj=axisswap +order=2,1 +step " + "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 " + "+step +proj=cart +ellps=WGS84 +step +proj=helmert +x=1 +y=2 " + "+z=3 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 " + "+step +proj=unitconvert +xy_in=rad +xy_out=deg +step " + "+proj=axisswap +order=2,1"); } // --------------------------------------------------------------------------- @@ -2096,7 +2117,7 @@ TEST_F(FactoryWithTmpDatabase, "NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL," "NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL," "NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL," - "NULL,NULL,NULL,NULL,NULL,NULL,0);")) + "NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);")) << last_error(); auto factoryOTHER = @@ -2123,7 +2144,7 @@ TEST_F(FactoryWithTmpDatabase, "NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL," "NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL," "NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL," - "NULL,NULL,NULL,NULL,NULL,NULL,0);")) + "NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);")) << last_error(); auto factoryOTHER = @@ -2613,7 +2634,7 @@ TEST_F(FactoryWithTmpDatabase, "NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL," "NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL," "NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL," - "NULL,NULL,NULL,NULL,NULL,NULL,0);")) + "NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);")) << last_error(); ASSERT_TRUE( @@ -2625,7 +2646,7 @@ TEST_F(FactoryWithTmpDatabase, "NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL," "NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL," "NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL," - "NULL,NULL,NULL,NULL,NULL,NULL,0);")) + "NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);")) << last_error(); auto dbContext = DatabaseContext::create(m_ctxt); @@ -2792,7 +2813,7 @@ TEST(factory, getMetadata) { EXPECT_EQ(ctxt->getMetadata("i_do_not_exist"), nullptr); const char *IGNF_VERSION = ctxt->getMetadata("IGNF.VERSION"); ASSERT_TRUE(IGNF_VERSION != nullptr); - EXPECT_EQ(std::string(IGNF_VERSION), "3.0.2"); + EXPECT_EQ(std::string(IGNF_VERSION), "3.0.3"); } // --------------------------------------------------------------------------- diff --git a/test/unit/test_io.cpp b/test/unit/test_io.cpp index 3d015e0c..294e765d 100644 --- a/test/unit/test_io.cpp +++ b/test/unit/test_io.cpp @@ -1640,6 +1640,77 @@ TEST(wkt_parse, wkt2_projected) { // --------------------------------------------------------------------------- +TEST(wkt_parse, wkt2_2018_projected_with_id_in_basegeodcrs) { + auto wkt = "PROJCRS[\"WGS 84 / UTM zone 31N\",\n" + " BASEGEOGCRS[\"WGS 84\",\n" + " DATUM[\"World Geodetic System 1984\",\n" + " ELLIPSOID[\"WGS 84\",6378137,298.257223563]],\n" + " ID[\"EPSG\",4326]],\n" + " CONVERSION[\"UTM zone 31N\",\n" + " METHOD[\"Transverse Mercator\"],\n" + " PARAMETER[\"Latitude of natural origin\",0],\n" + " PARAMETER[\"Longitude of natural origin\",3],\n" + " PARAMETER[\"Scale factor at natural origin\",0.9996],\n" + " PARAMETER[\"False easting\",500000],\n" + " PARAMETER[\"False northing\",0]],\n" + " CS[Cartesian,2],\n" + " AXIS[\"(E)\",east],\n" + " AXIS[\"(N)\",north],\n" + " UNIT[\"metre\",1],\n" + " ID[\"EPSG\",32631]]"; + auto obj = WKTParser().createFromWKT(wkt); + auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj); + ASSERT_TRUE(crs != nullptr); + ASSERT_EQ(crs->baseCRS()->identifiers().size(), 1U); + EXPECT_EQ(crs->baseCRS()->identifiers().front()->code(), "4326"); + + { + auto got_wkt = crs->exportToWKT( + WKTFormatter::create(WKTFormatter::Convention::WKT2_2018).get()); + EXPECT_TRUE(got_wkt.find("ID[\"EPSG\",4326]]") != std::string::npos) + << got_wkt; + } + + { + auto got_wkt = crs->exportToWKT( + WKTFormatter::create(WKTFormatter::Convention::WKT2_2018_SIMPLIFIED) + .get()); + EXPECT_TRUE(got_wkt.find("ID[\"EPSG\",4326]]") == std::string::npos) + << got_wkt; + } +} + +// --------------------------------------------------------------------------- + +TEST(wkt_parse, wkt2_2018_projected_no_id_but_id_in_basegeodcrs) { + auto wkt = "PROJCRS[\"WGS 84 / UTM zone 31N\",\n" + " BASEGEOGCRS[\"WGS 84\",\n" + " DATUM[\"World Geodetic System 1984\",\n" + " ELLIPSOID[\"WGS 84\",6378137,298.257223563]],\n" + " ID[\"EPSG\",4326]],\n" + " CONVERSION[\"UTM zone 31N\",\n" + " METHOD[\"Transverse Mercator\"],\n" + " PARAMETER[\"Latitude of natural origin\",0],\n" + " PARAMETER[\"Longitude of natural origin\",3],\n" + " PARAMETER[\"Scale factor at natural origin\",0.9996],\n" + " PARAMETER[\"False easting\",500000],\n" + " PARAMETER[\"False northing\",0]],\n" + " CS[Cartesian,2],\n" + " AXIS[\"(E)\",east],\n" + " AXIS[\"(N)\",north],\n" + " UNIT[\"metre\",1]]"; + auto obj = WKTParser().createFromWKT(wkt); + auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj); + ASSERT_TRUE(crs != nullptr); + + auto got_wkt = crs->exportToWKT( + WKTFormatter::create(WKTFormatter::Convention::WKT2_2018).get()); + EXPECT_TRUE(got_wkt.find("ID[\"EPSG\",4326]]") != std::string::npos) + << got_wkt; +} + +// --------------------------------------------------------------------------- + TEST(wkt_parse, wkt2_2018_simplified_projected) { auto wkt = "PROJCRS[\"WGS 84 / UTM zone 31N\",\n" " BASEGEOGCRS[\"WGS 84\",\n" @@ -2280,6 +2351,95 @@ TEST(wkt_parse, COORDINATEOPERATION) { GeographicCRS::EPSG_4979->nameStr()); EXPECT_EQ(transf->method()->nameStr(), "operationMethodName"); EXPECT_EQ(transf->parameterValues().size(), 1U); + + { + auto outWkt = transf->exportToWKT(WKTFormatter::create().get()); + EXPECT_EQ(replaceAll(replaceAll(outWkt, "\n", ""), " ", ""), + replaceAll(replaceAll(wkt, "\n", ""), " ", "")); + } +} + +// --------------------------------------------------------------------------- + +TEST(wkt_parse, COORDINATEOPERATION_wkt2018) { + + std::string src_wkt; + { + auto formatter = + WKTFormatter::create(WKTFormatter::Convention::WKT2_2018); + formatter->setOutputId(false); + src_wkt = GeographicCRS::EPSG_4326->exportToWKT(formatter.get()); + } + + std::string dst_wkt; + { + auto formatter = + WKTFormatter::create(WKTFormatter::Convention::WKT2_2018); + formatter->setOutputId(false); + dst_wkt = GeographicCRS::EPSG_4807->exportToWKT(formatter.get()); + } + + std::string interpolation_wkt; + { + auto formatter = + WKTFormatter::create(WKTFormatter::Convention::WKT2_2018); + formatter->setOutputId(false); + interpolation_wkt = + GeographicCRS::EPSG_4979->exportToWKT(formatter.get()); + } + + auto wkt = + "COORDINATEOPERATION[\"transformationName\",\n" + " VERSION[\"my version\"],\n" + " SOURCECRS[" + + src_wkt + "],\n" + " TARGETCRS[" + + dst_wkt + + "],\n" + " METHOD[\"operationMethodName\",\n" + " ID[\"codeSpaceOperationMethod\",\"codeOperationMethod\"]],\n" + " PARAMETERFILE[\"paramName\",\"foo.bin\"],\n" + " INTERPOLATIONCRS[" + + interpolation_wkt + + "],\n" + " OPERATIONACCURACY[0.1],\n" + " ID[\"codeSpaceTransformation\",\"codeTransformation\"],\n" + " REMARK[\"my remarks\"]]"; + + auto obj = WKTParser().createFromWKT(wkt); + auto transf = nn_dynamic_pointer_cast<Transformation>(obj); + ASSERT_TRUE(transf != nullptr); + EXPECT_EQ(transf->nameStr(), "transformationName"); + EXPECT_EQ(*transf->operationVersion(), "my version"); + ASSERT_EQ(transf->identifiers().size(), 1U); + EXPECT_EQ(transf->identifiers()[0]->code(), "codeTransformation"); + EXPECT_EQ(*(transf->identifiers()[0]->codeSpace()), + "codeSpaceTransformation"); + ASSERT_EQ(transf->coordinateOperationAccuracies().size(), 1U); + EXPECT_EQ(transf->coordinateOperationAccuracies()[0]->value(), "0.1"); + EXPECT_EQ(transf->sourceCRS()->nameStr(), + GeographicCRS::EPSG_4326->nameStr()); + EXPECT_EQ(transf->targetCRS()->nameStr(), + GeographicCRS::EPSG_4807->nameStr()); + ASSERT_TRUE(transf->interpolationCRS() != nullptr); + EXPECT_EQ(transf->interpolationCRS()->nameStr(), + GeographicCRS::EPSG_4979->nameStr()); + EXPECT_EQ(transf->method()->nameStr(), "operationMethodName"); + EXPECT_EQ(transf->parameterValues().size(), 1U); + + { + auto outWkt = transf->exportToWKT( + WKTFormatter::create(WKTFormatter::Convention::WKT2_2018).get()); + EXPECT_EQ(replaceAll(replaceAll(outWkt, "\n", ""), " ", ""), + replaceAll(replaceAll(wkt, "\n", ""), " ", "")); + } + + { + auto outWkt = transf->exportToWKT( + WKTFormatter::create(WKTFormatter::Convention::WKT2_2015).get()); + EXPECT_FALSE(outWkt.find("VERSION[\"my version\"],") != + std::string::npos); + } } // --------------------------------------------------------------------------- @@ -2339,6 +2499,7 @@ TEST(wkt_parse, CONCATENATEDOPERATION) { auto concat = nn_dynamic_pointer_cast<ConcatenatedOperation>(obj); ASSERT_TRUE(concat != nullptr); EXPECT_EQ(concat->nameStr(), "name"); + EXPECT_FALSE(concat->operationVersion().has_value()); ASSERT_EQ(concat->identifiers().size(), 1U); EXPECT_EQ(concat->identifiers()[0]->code(), "code"); EXPECT_EQ(*(concat->identifiers()[0]->codeSpace()), "codeSpace"); @@ -2487,6 +2648,7 @@ TEST(wkt_parse, auto wkt = "CONCATENATEDOPERATION[\"Inverse of UTM zone 11N + NAD27 to WGS 84 " "(79) + UTM zone 11N\",\n" + " VERSION[\"my version\"],\n" " SOURCECRS[\n" " PROJCRS[\"NAD27 / UTM zone 11N\",\n" " BASEGEOGCRS[\"NAD27\",\n" @@ -2639,6 +2801,7 @@ TEST(wkt_parse, auto obj = WKTParser().createFromWKT(wkt); auto concat = nn_dynamic_pointer_cast<ConcatenatedOperation>(obj); ASSERT_TRUE(concat != nullptr); + EXPECT_EQ(*concat->operationVersion(), "my version"); EXPECT_EQ(concat->exportToPROJString(PROJStringFormatter::create().get()), "+proj=pipeline +step +inv +proj=utm +zone=11 +ellps=clrk66 " @@ -5017,6 +5180,43 @@ TEST(wkt_parse, wkt1_esri_ups_south) { // --------------------------------------------------------------------------- +TEST(wkt_parse, wkt1_esri_gauss_kruger) { + auto wkt = "PROJCS[\"ETRS_1989_UWPP_2000_PAS_8\",GEOGCS[\"GCS_ETRS_1989\"," + "DATUM[\"D_ETRS_1989\"," + "SPHEROID[\"GRS_1980\",6378137.0,298.257222101]]," + "PRIMEM[\"Greenwich\",0.0]," + "UNIT[\"Degree\",0.0174532925199433]]," + "PROJECTION[\"Gauss_Kruger\"]," + "PARAMETER[\"False_Easting\",8500000.0]," + "PARAMETER[\"False_Northing\",0.0]," + "PARAMETER[\"Central_Meridian\",24.0]," + "PARAMETER[\"Scale_Factor\",0.999923]," + "PARAMETER[\"Latitude_Of_Origin\",0.0]," + "UNIT[\"Meter\",1.0]]"; + + auto dbContext = DatabaseContext::create(); + auto obj = WKTParser().attachDatabaseContext(dbContext).createFromWKT(wkt); + auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj); + ASSERT_TRUE(crs != nullptr); + + EXPECT_EQ( + crs->exportToWKT( + WKTFormatter::create(WKTFormatter::Convention::WKT1_ESRI, dbContext) + .get()), + wkt); + + auto crs2 = AuthorityFactory::create(dbContext, "ESRI") + ->createProjectedCRS("102177"); + + EXPECT_EQ( + crs2->exportToWKT( + WKTFormatter::create(WKTFormatter::Convention::WKT1_ESRI, dbContext) + .get()), + wkt); +} + +// --------------------------------------------------------------------------- + TEST(wkt_parse, invalid) { EXPECT_THROW(WKTParser().createFromWKT(""), ParsingException); EXPECT_THROW(WKTParser().createFromWKT("A"), ParsingException); @@ -6378,7 +6578,7 @@ TEST(io, projstringformatter_helmert_3_param_noop) { fmt->addParam("x", 0); fmt->addParam("y", 0); fmt->addParam("z", 0); - EXPECT_EQ(fmt->toString(), ""); + EXPECT_EQ(fmt->toString(), "+proj=noop"); } // --------------------------------------------------------------------------- @@ -6394,7 +6594,7 @@ TEST(io, projstringformatter_helmert_7_param_noop) { fmt->addParam("rz", 0); fmt->addParam("s", 0); fmt->addParam("convention", "position_vector"); - EXPECT_EQ(fmt->toString(), ""); + EXPECT_EQ(fmt->toString(), "+proj=noop"); } // --------------------------------------------------------------------------- @@ -6424,7 +6624,7 @@ TEST(io, projstringformatter_merge_consecutive_helmert_3_param_noop) { fmt->addParam("x", -10); fmt->addParam("y", -20); fmt->addParam("z", -30); - EXPECT_EQ(fmt->toString(), ""); + EXPECT_EQ(fmt->toString(), "+proj=noop"); } // --------------------------------------------------------------------------- @@ -6436,7 +6636,7 @@ TEST(io, projstringformatter_cart_grs80_wgs84) { fmt->addStep("cart"); fmt->setCurrentStepInverted(true); fmt->addParam("ellps", "GRS80"); - EXPECT_EQ(fmt->toString(), ""); + EXPECT_EQ(fmt->toString(), "+proj=noop"); } // --------------------------------------------------------------------------- @@ -7171,7 +7371,8 @@ TEST(io, projparse_longlat_axis_neu) { auto op = CoordinateOperationFactory::create()->createOperation( GeographicCRS::EPSG_4326, NN_NO_CHECK(crs)); ASSERT_TRUE(op != nullptr); - EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), ""); + EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), + "+proj=noop"); } // --------------------------------------------------------------------------- @@ -7274,7 +7475,7 @@ TEST(io, projparse_longlat_axisswap) { EXPECT_EQ( op->exportToPROJString(PROJStringFormatter::create().get()), (atoi(order1) == 2 && atoi(order2) == 1) - ? "" + ? "+proj=noop" : "+proj=pipeline +step +proj=axisswap +order=2,1 " "+step +proj=axisswap +order=" + std::string(order1) + "," + order2); @@ -8611,6 +8812,39 @@ TEST(io, createFromUserInput) { EXPECT_THROW( createFromUserInput("urn:ogc:def:unhandled:EPSG::4326", dbContext), ParsingException); + EXPECT_THROW(createFromUserInput("urn:ogc:def:crs:non_existing_auth::4326", + dbContext), + NoSuchAuthorityCodeException); + EXPECT_THROW(createFromUserInput( + "urn:ogc:def:crs,crs:EPSG::2393,unhandled_type:EPSG::5717", + dbContext), + ParsingException); + EXPECT_THROW(createFromUserInput( + "urn:ogc:def:crs,crs:EPSG::2393,crs:EPSG::unexisting_code", + dbContext), + NoSuchAuthorityCodeException); + EXPECT_THROW( + createFromUserInput( + "urn:ogc:def:crs,crs:EPSG::2393::extra_element,crs:EPSG::EPSG", + dbContext), + ParsingException); + EXPECT_THROW(createFromUserInput("urn:ogc:def:coordinateOperation," + "coordinateOperation:EPSG::3895," + "unhandled_type:EPSG::1618", + dbContext), + ParsingException); + EXPECT_THROW( + createFromUserInput("urn:ogc:def:coordinateOperation," + "coordinateOperation:EPSG::3895," + "coordinateOperation:EPSG::unexisting_code", + dbContext), + NoSuchAuthorityCodeException); + EXPECT_THROW( + createFromUserInput("urn:ogc:def:coordinateOperation," + "coordinateOperation:EPSG::3895::extra_element," + "coordinateOperation:EPSG::1618", + dbContext), + ParsingException); EXPECT_NO_THROW(createFromUserInput("+proj=longlat", nullptr)); EXPECT_NO_THROW(createFromUserInput("EPSG:4326", dbContext)); @@ -8625,6 +8859,31 @@ TEST(io, createFromUserInput) { createFromUserInput("urn:ogc:def:meridian:EPSG::8901", dbContext)); EXPECT_NO_THROW( createFromUserInput("urn:ogc:def:ellipsoid:EPSG::7030", dbContext)); + { + auto obj = createFromUserInput("EPSG:2393+5717", dbContext); + auto crs = nn_dynamic_pointer_cast<CompoundCRS>(obj); + ASSERT_TRUE(crs != nullptr); + EXPECT_EQ(crs->nameStr(), + "KKJ / Finland Uniform Coordinate System + N60 height"); + } + { + auto obj = createFromUserInput( + "urn:ogc:def:crs,crs:EPSG::2393,crs:EPSG::5717", dbContext); + auto crs = nn_dynamic_pointer_cast<CompoundCRS>(obj); + ASSERT_TRUE(crs != nullptr); + EXPECT_EQ(crs->nameStr(), + "KKJ / Finland Uniform Coordinate System + N60 height"); + } + { + auto obj = createFromUserInput("urn:ogc:def:coordinateOperation," + "coordinateOperation:EPSG::3895," + "coordinateOperation:EPSG::1618", + dbContext); + auto concat = nn_dynamic_pointer_cast<ConcatenatedOperation>(obj); + ASSERT_TRUE(concat != nullptr); + EXPECT_EQ(concat->nameStr(), + "MGI (Ferro) to MGI (1) + MGI to WGS 84 (3)"); + } EXPECT_NO_THROW(createFromUserInput( "GEOGCRS[\"WGS 84\",\n" " DATUM[\"World Geodetic System 1984\",\n" diff --git a/test/unit/test_operation.cpp b/test/unit/test_operation.cpp index 90deb661..5ac1609d 100644 --- a/test/unit/test_operation.cpp +++ b/test/unit/test_operation.cpp @@ -218,6 +218,11 @@ TEST(operation, SingleOperation) { EXPECT_TRUE(sop1->isEquivalentTo(sop1.get())); EXPECT_FALSE(sop1->isEquivalentTo(createUnrelatedObject().get())); + EXPECT_TRUE( + sop1->isEquivalentTo(sop1->CoordinateOperation::shallowClone().get())); + EXPECT_TRUE(sop1->inverse()->isEquivalentTo( + sop1->inverse()->CoordinateOperation::shallowClone().get())); + auto sop2 = Transformation::create( PropertyMap(), nn_static_pointer_cast<CRS>(GeographicCRS::EPSG_4326), nn_static_pointer_cast<CRS>(GeographicCRS::EPSG_4807), @@ -442,7 +447,6 @@ TEST(operation, concatenated_operation) { { auto formatter = WKTFormatter::create(WKTFormatter::Convention::WKT2_2018); - formatter->setOutputId(false); src_wkt = GeographicCRS::EPSG_4326->exportToWKT(formatter.get()); } @@ -450,7 +454,6 @@ TEST(operation, concatenated_operation) { { auto formatter = WKTFormatter::create(WKTFormatter::Convention::WKT2_2018); - formatter->setOutputId(false); dst_wkt = GeographicCRS::EPSG_4979->exportToWKT(formatter.get()); } @@ -458,7 +461,6 @@ TEST(operation, concatenated_operation) { { auto formatter = WKTFormatter::create(WKTFormatter::Convention::WKT2_2018); - formatter->setOutputId(false); step1_wkt = transf_1->exportToWKT(formatter.get()); } @@ -466,7 +468,6 @@ TEST(operation, concatenated_operation) { { auto formatter = WKTFormatter::create(WKTFormatter::Convention::WKT2_2018); - formatter->setOutputId(false); step2_wkt = transf_2->exportToWKT(formatter.get()); } @@ -514,6 +515,8 @@ TEST(operation, concatenated_operation) { EXPECT_TRUE(concat->isEquivalentTo(concat.get())); EXPECT_FALSE(concat->isEquivalentTo(createUnrelatedObject().get())); + EXPECT_TRUE(concat->isEquivalentTo( + concat->CoordinateOperation::shallowClone().get())); EXPECT_FALSE( ConcatenatedOperation::create(PropertyMap(), std::vector<CoordinateOperationNNPtr>{ @@ -565,12 +568,12 @@ TEST(operation, transformation_createGeocentricTranslations) { EXPECT_EQ(inv_transf_as_transf->getTOWGS84Parameters(), expected_inv); EXPECT_EQ(transf->exportToPROJString(PROJStringFormatter::create().get()), - "+proj=pipeline +step +proj=push +v_3 +step +proj=axisswap " - "+order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step " - "+proj=cart +ellps=GRS80 +step +proj=helmert +x=1 +y=2 +z=3 " - "+step +inv +proj=cart +ellps=WGS84 +step +proj=unitconvert " - "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1 +step " - "+proj=pop +v_3"); + "+proj=pipeline +step +proj=axisswap +order=2,1 +step " + "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 " + "+step +proj=cart +ellps=GRS80 +step +proj=helmert +x=1 +y=2 " + "+z=3 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 " + "+step +proj=unitconvert +xy_in=rad +xy_out=deg +step " + "+proj=axisswap +order=2,1"); } // --------------------------------------------------------------------------- @@ -640,7 +643,7 @@ TEST(operation, transformation_createGeocentricTranslations_null) { EXPECT_EQ(transf->inverse()->exportToPROJString( PROJStringFormatter::create().get()), - ""); + "+proj=noop"); } // --------------------------------------------------------------------------- @@ -673,13 +676,13 @@ TEST(operation, transformation_createPositionVector) { EXPECT_EQ(transf->getTOWGS84Parameters(), expected); EXPECT_EQ(transf->exportToPROJString(PROJStringFormatter::create().get()), - "+proj=pipeline +step +proj=push +v_3 +step +proj=axisswap " - "+order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step " - "+proj=cart +ellps=GRS80 +step +proj=helmert +x=1 +y=2 +z=3 " - "+rx=4 +ry=5 +rz=6 +s=7 +convention=position_vector +step +inv " - "+proj=cart +ellps=WGS84 +step +proj=unitconvert +xy_in=rad " - "+xy_out=deg +step +proj=axisswap +order=2,1 +step +proj=pop " - "+v_3"); + "+proj=pipeline +step +proj=axisswap +order=2,1 +step " + "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 " + "+step +proj=cart +ellps=GRS80 +step +proj=helmert +x=1 +y=2 " + "+z=3 +rx=4 +ry=5 +rz=6 +s=7 +convention=position_vector +step " + "+inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step " + "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap " + "+order=2,1"); auto inv_transf = transf->inverse(); ASSERT_EQ(inv_transf->coordinateOperationAccuracies().size(), 1U); @@ -696,12 +699,12 @@ TEST(operation, transformation_createPositionVector) { #else EXPECT_EQ( inv_transf->exportToPROJString(PROJStringFormatter::create().get()), - "+proj=pipeline +step +proj=push +v_3 +step +proj=axisswap +order=2,1 " - "+step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=cart " - "+ellps=WGS84 +step +inv +proj=helmert +x=1 +y=2 +z=3 +rx=4 +ry=5 " - "+rz=6 +s=7 +convention=position_vector +step +inv +proj=cart " - "+ellps=GRS80 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step " - "+proj=axisswap +order=2,1 +step +proj=pop +v_3"); + "+proj=pipeline +step +proj=axisswap +order=2,1 +step " + "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 +step " + "+proj=cart +ellps=WGS84 +step +inv +proj=helmert +x=1 +y=2 +z=3 +rx=4 " + "+ry=5 +rz=6 +s=7 +convention=position_vector +step +inv +proj=cart " + "+ellps=GRS80 +step +proj=pop +v_3 +step +proj=unitconvert +xy_in=rad " + "+xy_out=deg +step +proj=axisswap +order=2,1"); // In WKT, use approximate formula auto wkt = inv_transf->exportToWKT(WKTFormatter::create().get()); @@ -742,13 +745,13 @@ TEST(operation, transformation_createCoordinateFrameRotation) { EXPECT_EQ(params, expected); EXPECT_EQ(transf->exportToPROJString(PROJStringFormatter::create().get()), - "+proj=pipeline +step +proj=push +v_3 +step +proj=axisswap " - "+order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step " - "+proj=cart +ellps=GRS80 +step +proj=helmert +x=1 +y=2 +z=3 " - "+rx=-4 +ry=-5 +rz=-6 +s=7 +convention=coordinate_frame +step " - "+inv +proj=cart +ellps=WGS84 +step +proj=unitconvert +xy_in=rad " - "+xy_out=deg +step +proj=axisswap +order=2,1 +step +proj=pop " - "+v_3"); + "+proj=pipeline +step +proj=axisswap +order=2,1 +step " + "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 " + "+step +proj=cart +ellps=GRS80 +step +proj=helmert +x=1 +y=2 " + "+z=3 +rx=-4 +ry=-5 +rz=-6 +s=7 +convention=coordinate_frame " + "+step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step " + "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap " + "+order=2,1"); auto inv_transf = transf->inverse(); ASSERT_EQ(inv_transf->coordinateOperationAccuracies().size(), 0U); @@ -765,12 +768,12 @@ TEST(operation, transformation_createCoordinateFrameRotation) { #else EXPECT_EQ( inv_transf->exportToPROJString(PROJStringFormatter::create().get()), - "+proj=pipeline +step +proj=push +v_3 +step +proj=axisswap +order=2,1 " - "+step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=cart " - "+ellps=WGS84 +step +inv +proj=helmert +x=1 +y=2 +z=3 +rx=-4 +ry=-5 " - "+rz=-6 +s=7 +convention=coordinate_frame +step +inv +proj=cart " - "+ellps=GRS80 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step " - "+proj=axisswap +order=2,1 +step +proj=pop +v_3"); + "+proj=pipeline +step +proj=axisswap +order=2,1 +step " + "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 +step " + "+proj=cart +ellps=WGS84 +step +inv +proj=helmert +x=1 +y=2 +z=3 " + "+rx=-4 +ry=-5 +rz=-6 +s=7 +convention=coordinate_frame +step +inv " + "+proj=cart +ellps=GRS80 +step +proj=pop +v_3 +step +proj=unitconvert " + "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1"); // In WKT, use approximate formula auto wkt = inv_transf->exportToWKT(WKTFormatter::create().get()); @@ -960,7 +963,7 @@ TEST(operation, transformation_successive_helmert_noop) { std::vector<PositionalAccuracyNNPtr>{}); EXPECT_EQ(concat->exportToPROJString(PROJStringFormatter::create().get()), - ""); + "+proj=noop"); } // --------------------------------------------------------------------------- @@ -4054,6 +4057,11 @@ TEST(operation, conversion_inverse) { EXPECT_TRUE(inv->isEquivalentTo(inv.get())); EXPECT_FALSE(inv->isEquivalentTo(createUnrelatedObject().get())); + + EXPECT_TRUE( + conv->isEquivalentTo(conv->CoordinateOperation::shallowClone().get())); + EXPECT_TRUE( + inv->isEquivalentTo(inv->CoordinateOperation::shallowClone().get())); } // --------------------------------------------------------------------------- @@ -4135,7 +4143,7 @@ TEST(operation, PROJ_based_empty) { SingleOperation::createPROJBased(PropertyMap(), "", nullptr, nullptr); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), - ""); + "+proj=noop"); EXPECT_EQ(conv->exportToWKT(WKTFormatter::create().get()), "CONVERSION[\"PROJ-based coordinate operation\",\n" @@ -4148,7 +4156,7 @@ TEST(operation, PROJ_based_empty) { EXPECT_EQ(conv->inverse()->exportToPROJString( PROJStringFormatter::create().get()), - ""); + "+proj=noop"); } // --------------------------------------------------------------------------- @@ -4199,17 +4207,18 @@ TEST(operation, geogCRS_to_geogCRS_context_default) { EXPECT_EQ(list[0]->getEPSGCode(), 15994); // Romania - 3m EXPECT_EQ(list[1]->getEPSGCode(), 1644); // Poland - 1m EXPECT_EQ(list[2]->nameStr(), - "Null geographic offset from Pulkovo 1942(58) to ETRS89"); + "Ballpark geographic offset from Pulkovo 1942(58) to ETRS89"); EXPECT_EQ( list[0]->exportToPROJString(PROJStringFormatter::create().get()), - "+proj=pipeline +step +proj=push +v_3 +step +proj=axisswap " - "+order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step " - "+proj=cart +ellps=krass +step +proj=helmert +x=2.3287 " + "+proj=pipeline +step +proj=axisswap +order=2,1 +step " + "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 " + "+step +proj=cart +ellps=krass +step +proj=helmert +x=2.3287 " "+y=-147.0425 +z=-92.0802 +rx=0.3092483 +ry=-0.32482185 " "+rz=-0.49729934 +s=5.68906266 +convention=coordinate_frame +step " - "+inv +proj=cart +ellps=GRS80 +step +proj=unitconvert +xy_in=rad " - "+xy_out=deg +step +proj=axisswap +order=2,1 +step +proj=pop +v_3"); + "+inv +proj=cart +ellps=GRS80 +step +proj=pop +v_3 +step " + "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap " + "+order=2,1"); } // Reverse case @@ -4224,13 +4233,14 @@ TEST(operation, geogCRS_to_geogCRS_context_default) { EXPECT_EQ( list[0]->exportToPROJString(PROJStringFormatter::create().get()), - "+proj=pipeline +step +proj=push +v_3 +step +proj=axisswap " - "+order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step " - "+proj=cart +ellps=GRS80 +step +inv +proj=helmert +x=2.3287 " + "+proj=pipeline +step +proj=axisswap +order=2,1 +step " + "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 " + "+step +proj=cart +ellps=GRS80 +step +inv +proj=helmert +x=2.3287 " "+y=-147.0425 +z=-92.0802 +rx=0.3092483 +ry=-0.32482185 " "+rz=-0.49729934 +s=5.68906266 +convention=coordinate_frame +step " - "+inv +proj=cart +ellps=krass +step +proj=unitconvert +xy_in=rad " - "+xy_out=deg +step +proj=axisswap +order=2,1 +step +proj=pop +v_3"); + "+inv +proj=cart +ellps=krass +step +proj=pop +v_3 +step " + "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap " + "+order=2,1"); } } @@ -4330,7 +4340,7 @@ TEST(operation, geogCRS_to_geogCRS_context_filter_bbox) { ASSERT_EQ(list.size(), 1U); EXPECT_EQ( list[0]->exportToPROJString(PROJStringFormatter::create().get()), - ""); + "+proj=noop"); } } @@ -4346,7 +4356,7 @@ TEST(operation, geogCRS_to_geogCRS_context_incompatible_area) { ctxt); ASSERT_EQ(list.size(), 1U); EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()), - ""); + "+proj=noop"); } // --------------------------------------------------------------------------- @@ -4362,26 +4372,20 @@ TEST(operation, geogCRS_to_geogCRS_context_inverse_needed) { authFactory->createCoordinateReferenceSystem("4275"), // NTF authFactory->createCoordinateReferenceSystem("4258"), // ETRS89 ctxt); - ASSERT_EQ(list.size(), 3U); + ASSERT_EQ(list.size(), 2U); EXPECT_EQ( list[0]->exportToPROJString(PROJStringFormatter::create().get()), - "+proj=pipeline +step +proj=push +v_3 +step +proj=axisswap " - "+order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step " - "+proj=cart +ellps=clrk80ign +step +proj=helmert +x=-168 +y=-60 " - "+z=320 +step +inv +proj=cart +ellps=GRS80 +step +proj=unitconvert " - "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1 +step " - "+proj=pop +v_3"); + "+proj=pipeline +step +proj=axisswap +order=2,1 +step " + "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 " + "+step +proj=cart +ellps=clrk80ign +step +proj=helmert +x=-168 " + "+y=-60 +z=320 +step +inv +proj=cart +ellps=GRS80 +step +proj=pop " + "+v_3 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step " + "+proj=axisswap +order=2,1"); EXPECT_EQ(list[1]->exportToPROJString( PROJStringFormatter::create( PROJStringFormatter::Convention::PROJ_5, authFactory->databaseContext()) .get()), - ""); - EXPECT_EQ(list[2]->exportToPROJString( - PROJStringFormatter::create( - PROJStringFormatter::Convention::PROJ_5, - authFactory->databaseContext()) - .get()), "+proj=pipeline +step +proj=axisswap +order=2,1 +step " "+proj=unitconvert +xy_in=deg +xy_out=rad +step " "+proj=hgridshift +grids=ntf_r93.gsb +step +proj=unitconvert " @@ -4512,7 +4516,8 @@ TEST(operation, geogCRS_to_geogCRS_noop) { GeographicCRS::EPSG_4326, GeographicCRS::EPSG_4326); ASSERT_TRUE(op != nullptr); EXPECT_EQ(op->nameStr(), "Null geographic offset from WGS 84 to WGS 84"); - EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), ""); + EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), + "+proj=noop"); EXPECT_EQ(op->inverse()->nameStr(), op->nameStr()); } @@ -4659,7 +4664,7 @@ TEST(operation, geogCRS_to_geogCRS_CH1903_to_CH1903plus_context) { EXPECT_EQ(list[0]->nameStr(), "CH1903 to ETRS89 (1) + Inverse of CH1903+ to ETRS89 (1)"); EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()), - ""); + "+proj=noop"); EXPECT_EQ(list[1]->nameStr(), "CH1903 to CH1903+ (1)"); EXPECT_EQ(list[1]->exportToPROJString(PROJStringFormatter::create().get()), @@ -4754,6 +4759,52 @@ TEST(operation, geogCRS_to_geogCRS_3D) { // --------------------------------------------------------------------------- +TEST(operation, geogCRS_without_id_to_geogCRS_3D_context) { + auto authFactory = + AuthorityFactory::create(DatabaseContext::create(), "EPSG"); + auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0); + auto src = + authFactory->createCoordinateReferenceSystem("4289"); // Amersfoort + auto dst = + authFactory->createCoordinateReferenceSystem("4937"); // ETRS89 3D + auto list = + CoordinateOperationFactory::create()->createOperations(src, dst, ctxt); + ASSERT_GE(list.size(), 1U); + auto wkt2 = "GEOGCRS[\"unnamed\",\n" + " DATUM[\"Amersfoort\",\n" + " ELLIPSOID[\"Bessel 1841\",6377397.155,299.1528128,\n" + " LENGTHUNIT[\"metre\",1]]],\n" + " PRIMEM[\"Greenwich\",0,\n" + " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" + " CS[ellipsoidal,2],\n" + " AXIS[\"geodetic latitude (Lat)\",north,\n" + " ORDER[1],\n" + " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" + " AXIS[\"geodetic longitude (Lon)\",east,\n" + " ORDER[2],\n" + " ANGLEUNIT[\"degree\",0.0174532925199433]]," + " USAGE[\n" + " SCOPE[\"unknown\"],\n" + " AREA[\"Netherlands - onshore\"],\n" + " BBOX[50.75,3.2,53.7,7.22]]]\n"; + + auto obj = WKTParser().createFromWKT(wkt2); + auto src_from_wkt2 = nn_dynamic_pointer_cast<CRS>(obj); + ASSERT_TRUE(src_from_wkt2 != nullptr); + auto list2 = CoordinateOperationFactory::create()->createOperations( + NN_NO_CHECK(src_from_wkt2), dst, ctxt); + ASSERT_GE(list.size(), list2.size()); + for (size_t i = 0; i < list.size(); i++) { + const auto &op = list[i]; + const auto &op2 = list2[i]; + EXPECT_TRUE( + op->isEquivalentTo(op2.get(), IComparable::Criterion::EQUIVALENT)) + << op->nameStr() << " " << op2->nameStr(); + } +} + +// --------------------------------------------------------------------------- + TEST(operation, geocentricCRS_to_geogCRS_same_datum) { auto op = CoordinateOperationFactory::create()->createOperation( @@ -4772,9 +4823,10 @@ TEST(operation, geocentricCRS_to_geogCRS_different_datum) { auto op = CoordinateOperationFactory::create()->createOperation( createGeocentricDatumWGS84(), GeographicCRS::EPSG_4269); ASSERT_TRUE(op != nullptr); - EXPECT_EQ(op->nameStr(), "Null geocentric translation from WGS 84 to NAD83 " - "(geocentric) + Conversion from NAD83 " - "(geocentric) to NAD83"); + EXPECT_EQ(op->nameStr(), + "Ballpark geocentric translation from WGS 84 to NAD83 " + "(geocentric) + Conversion from NAD83 " + "(geocentric) to NAD83"); EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), "+proj=pipeline +step +inv +proj=cart +ellps=GRS80 +step " "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap " @@ -4789,7 +4841,7 @@ TEST(operation, geogCRS_to_geocentricCRS_different_datum) { GeographicCRS::EPSG_4269, createGeocentricDatumWGS84()); ASSERT_TRUE(op != nullptr); EXPECT_EQ(op->nameStr(), "Conversion from NAD83 to NAD83 (geocentric) + " - "Null geocentric translation from NAD83 " + "Ballpark geocentric translation from NAD83 " "(geocentric) to WGS 84"); EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), "+proj=pipeline +step +proj=axisswap +order=2,1 +step " @@ -4805,8 +4857,9 @@ TEST(operation, geocentricCRS_to_geocentricCRS_noop) { createGeocentricDatumWGS84(), createGeocentricDatumWGS84()); ASSERT_TRUE(op != nullptr); EXPECT_EQ(op->nameStr(), - "Null geocentric translation from WGS 84 to WGS 84"); - EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), ""); + "Ballpark geocentric translation from WGS 84 to WGS 84"); + EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), + "+proj=noop"); EXPECT_EQ(op->inverse()->nameStr(), op->nameStr()); } @@ -4902,6 +4955,24 @@ TEST(operation, geogCRS_geocentricCRS_same_datum_to_context) { // --------------------------------------------------------------------------- TEST(operation, + geog2D_to_geog3D_same_datum_but_with_potential_other_pivot_context) { + // Check that when going from geog2D to geog3D of same datum, we don't + // try to go through a WGS84 pivot... + auto authFactory = + AuthorityFactory::create(DatabaseContext::create(), "EPSG"); + auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0); + auto list = CoordinateOperationFactory::create()->createOperations( + authFactory->createCoordinateReferenceSystem("5365"), // CR 05 2D + authFactory->createCoordinateReferenceSystem("5364"), // CR 05 3D + ctxt); + ASSERT_EQ(list.size(), 1U); + EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()), + "+proj=noop"); +} + +// --------------------------------------------------------------------------- + +TEST(operation, geogCRS_to_geogCRS_different_datum_though_geocentric_transform_context) { auto authFactory = AuthorityFactory::create(DatabaseContext::create(), "EPSG"); @@ -5179,6 +5250,50 @@ TEST(operation, projCRS_to_geogCRS) { // --------------------------------------------------------------------------- +TEST(operation, projCRS_no_id_to_geogCRS_context) { + auto authFactory = + AuthorityFactory::create(DatabaseContext::create(), "EPSG"); + auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0); + auto src = authFactory->createCoordinateReferenceSystem( + "28992"); // Amersfoort / RD New + auto dst = + authFactory->createCoordinateReferenceSystem("4258"); // ETRS89 2D + auto list = + CoordinateOperationFactory::create()->createOperations(src, dst, ctxt); + ASSERT_GE(list.size(), 1U); + auto wkt2 = + "PROJCRS[\"unknown\",\n" + " BASEGEOGCRS[\"Amersfoort\",\n" + " DATUM[\"Amersfoort\",\n" + " ELLIPSOID[\"Bessel 1841\",6377397.155,299.1528128]]],\n" + " CONVERSION[\"unknown\",\n" + " METHOD[\"Oblique Stereographic\"],\n" + " PARAMETER[\"Latitude of natural origin\",52.1561605555556],\n" + " PARAMETER[\"Longitude of natural origin\",5.38763888888889],\n" + " PARAMETER[\"Scale factor at natural origin\",0.9999079],\n" + " PARAMETER[\"False easting\",155000],\n" + " PARAMETER[\"False northing\",463000]],\n" + " CS[Cartesian,2],\n" + " AXIS[\"(E)\",east],\n" + " AXIS[\"(N)\",north],\n" + " LENGTHUNIT[\"metre\",1],\n" + " ID[\"EPSG\",28992]]"; + auto obj = WKTParser().createFromWKT(wkt2); + auto src_from_wkt2 = nn_dynamic_pointer_cast<CRS>(obj); + ASSERT_TRUE(src_from_wkt2 != nullptr); + auto list2 = CoordinateOperationFactory::create()->createOperations( + NN_NO_CHECK(src_from_wkt2), dst, ctxt); + ASSERT_GE(list.size(), list2.size() - 1); + for (size_t i = 0; i < list.size(); i++) { + const auto &op = list[i]; + const auto &op2 = list2[i]; + EXPECT_TRUE( + op->isEquivalentTo(op2.get(), IComparable::Criterion::EQUIVALENT)); + } +} + +// --------------------------------------------------------------------------- + TEST(operation, projCRS_to_projCRS) { auto op = CoordinateOperationFactory::create()->createOperation( @@ -5281,6 +5396,39 @@ TEST(operation, projCRS_to_projCRS_context_incompatible_areas) { // --------------------------------------------------------------------------- +TEST(operation, projCRS_to_projCRS_context_incompatible_areas_ballpark) { + auto authFactory = + AuthorityFactory::create(DatabaseContext::create(), "EPSG"); + auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0); + auto list = CoordinateOperationFactory::create()->createOperations( + authFactory->createCoordinateReferenceSystem("26711"), // UTM 11 NAD27 + authFactory->createCoordinateReferenceSystem( + "3034"), // ETRS89 / LCC Europe + ctxt); + ASSERT_GE(list.size(), 1U); + EXPECT_TRUE(list[0]->hasBallparkTransformation()); +} + +// --------------------------------------------------------------------------- + +TEST( + operation, + projCRS_to_projCRS_context_incompatible_areas_crs_extent_use_intersection) { + auto authFactory = + AuthorityFactory::create(DatabaseContext::create(), "EPSG"); + auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0); + ctxt->setSourceAndTargetCRSExtentUse( + CoordinateOperationContext::SourceTargetCRSExtentUse::INTERSECTION); + auto list = CoordinateOperationFactory::create()->createOperations( + authFactory->createCoordinateReferenceSystem("26711"), // UTM 11 NAD27 + authFactory->createCoordinateReferenceSystem( + "3034"), // ETRS89 / LCC Europe + ctxt); + ASSERT_GE(list.size(), 0U); +} + +// --------------------------------------------------------------------------- + TEST(operation, projCRS_to_projCRS_north_pole_inverted_axis) { auto authFactory = @@ -5317,6 +5465,37 @@ TEST(operation, projCRS_to_projCRS_south_pole_inverted_axis) { // --------------------------------------------------------------------------- +TEST(operation, projCRS_to_projCRS_through_geog3D) { + // Check that when going from projCRS to projCRS, using + // geog2D-->geog3D-->geog3D-->geog2D we do not have issues with + // inconsistent CRS chaining, due to how we 'hack' a bit some intermediate + // steps + auto authFactory = + AuthorityFactory::create(DatabaseContext::create(), "EPSG"); + auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0); + auto list = CoordinateOperationFactory::create()->createOperations( + authFactory->createCoordinateReferenceSystem("5367"), // CR05 / CRTM05 + authFactory->createCoordinateReferenceSystem( + "8908"), // CR-SIRGAS / CRTM05 + ctxt); + ASSERT_EQ(list.size(), 1U); + EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()), + "+proj=pipeline +step +proj=axisswap +order=2,1 " + "+step +inv +proj=tmerc +lat_0=0 +lon_0=-84 +k=0.9999 " + "+x_0=500000 +y_0=0 +ellps=WGS84 " + "+step +proj=push +v_3 " + "+step +proj=cart +ellps=WGS84 " + "+step +proj=helmert +x=-0.16959 +y=0.35312 +z=0.51846 " + "+rx=-0.03385 +ry=0.16325 +rz=-0.03446 +s=0.03693 " + "+convention=position_vector " + "+step +inv +proj=cart +ellps=GRS80 " + "+step +proj=pop +v_3 " + "+step +proj=tmerc +lat_0=0 +lon_0=-84 +k=0.9999 +x_0=500000 " + "+y_0=0 +ellps=GRS80"); +} + +// --------------------------------------------------------------------------- + TEST(operation, boundCRS_of_geogCRS_to_geogCRS) { auto boundCRS = BoundCRS::createFromTOWGS84( GeographicCRS::EPSG_4807, std::vector<double>{1, 2, 3, 4, 5, 6, 7}); @@ -5324,14 +5503,14 @@ TEST(operation, boundCRS_of_geogCRS_to_geogCRS) { boundCRS, GeographicCRS::EPSG_4326); ASSERT_TRUE(op != nullptr); EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), - "+proj=pipeline +step +proj=push +v_3 +step +proj=axisswap " - "+order=2,1 +step +proj=unitconvert +xy_in=grad +xy_out=rad " - "+step +inv +proj=longlat +ellps=clrk80ign +pm=paris +step " - "+proj=cart +ellps=clrk80ign +step +proj=helmert +x=1 +y=2 +z=3 " - "+rx=4 +ry=5 +rz=6 +s=7 +convention=position_vector +step +inv " - "+proj=cart +ellps=WGS84 +step +proj=unitconvert +xy_in=rad " - "+xy_out=deg +step +proj=axisswap +order=2,1 +step +proj=pop " - "+v_3"); + "+proj=pipeline +step +proj=axisswap +order=2,1 +step " + "+proj=unitconvert +xy_in=grad +xy_out=rad +step +inv " + "+proj=longlat +ellps=clrk80ign +pm=paris +step +proj=push +v_3 " + "+step +proj=cart +ellps=clrk80ign +step +proj=helmert +x=1 +y=2 " + "+z=3 +rx=4 +ry=5 +rz=6 +s=7 +convention=position_vector +step " + "+inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step " + "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap " + "+order=2,1"); } // --------------------------------------------------------------------------- @@ -5345,13 +5524,13 @@ TEST(operation, boundCRS_of_geogCRS_to_geogCRS_with_area) { boundCRS, authFactory->createCoordinateReferenceSystem("4326")); ASSERT_TRUE(op != nullptr); EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), - "+proj=pipeline +step +proj=push +v_3 +step +proj=axisswap " - "+order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step " - "+proj=cart +ellps=clrk66 +step +proj=helmert +x=1 +y=2 +z=3 " - "+rx=4 +ry=5 +rz=6 +s=7 +convention=position_vector +step +inv " - "+proj=cart +ellps=WGS84 +step +proj=unitconvert +xy_in=rad " - "+xy_out=deg +step +proj=axisswap +order=2,1 +step +proj=pop " - "+v_3"); + "+proj=pipeline +step +proj=axisswap +order=2,1 +step " + "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 " + "+step +proj=cart +ellps=clrk66 +step +proj=helmert +x=1 +y=2 " + "+z=3 +rx=4 +ry=5 +rz=6 +s=7 +convention=position_vector +step " + "+inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step " + "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap " + "+order=2,1"); } // --------------------------------------------------------------------------- @@ -5387,8 +5566,8 @@ TEST(operation, createOperation_boundCRS_identified_by_datum) { NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dest)); ASSERT_TRUE(op != nullptr); EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), - "+proj=pipeline +step +proj=push +v_3 +step +proj=unitconvert " - "+xy_in=deg +xy_out=rad +step +proj=cart +ellps=WGS84 +step " + "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad " + "+step +proj=push +v_3 +step +proj=cart +ellps=WGS84 +step " "+proj=helmert +x=263 +y=-6 +z=-431 +step +inv +proj=cart " "+ellps=clrk80ign +step +proj=pop +v_3 +step +proj=utm +zone=32 " "+ellps=clrk80ign"); @@ -5461,13 +5640,11 @@ TEST(operation, boundCRS_of_projCRS_to_geogCRS) { ASSERT_TRUE(op != nullptr); EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), "+proj=pipeline +step +inv +proj=utm +zone=31 +ellps=clrk80ign " - "+pm=paris +step +proj=longlat +ellps=clrk80ign +pm=paris +step " - "+proj=push +v_3 +step +inv +proj=longlat +ellps=clrk80ign " - "+pm=paris +step +proj=cart +ellps=clrk80ign +step +proj=helmert " - "+x=1 +y=2 +z=3 +rx=4 +ry=5 +rz=6 +s=7 " - "+convention=position_vector +step +inv +proj=cart +ellps=WGS84 " - "+step +proj=unitconvert +xy_in=rad +xy_out=deg +step " - "+proj=axisswap +order=2,1 +step +proj=pop +v_3"); + "+pm=paris +step +proj=push +v_3 +step +proj=cart " + "+ellps=clrk80ign +step +proj=helmert +x=1 +y=2 +z=3 +rx=4 +ry=5 " + "+rz=6 +s=7 +convention=position_vector +step +inv +proj=cart " + "+ellps=WGS84 +step +proj=pop +v_3 +step +proj=unitconvert " + "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1"); } // --------------------------------------------------------------------------- @@ -5483,13 +5660,45 @@ TEST(operation, boundCRS_of_geogCRS_to_projCRS) { CoordinateOperationFactory::create()->createOperation(boundCRS, utm31); ASSERT_TRUE(op != nullptr); EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), - "+proj=pipeline +step +proj=push +v_3 +step +proj=axisswap " - "+order=2,1 +step +proj=unitconvert +xy_in=grad +xy_out=rad " - "+step +inv +proj=longlat +ellps=clrk80ign +pm=paris +step " - "+proj=cart +ellps=clrk80ign +step +proj=helmert +x=1 +y=2 +z=3 " - "+rx=4 +ry=5 +rz=6 +s=7 +convention=position_vector +step +inv " - "+proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=utm " - "+zone=31 +ellps=WGS84"); + "+proj=pipeline +step +proj=axisswap +order=2,1 +step " + "+proj=unitconvert +xy_in=grad +xy_out=rad +step +inv " + "+proj=longlat +ellps=clrk80ign +pm=paris +step +proj=push +v_3 " + "+step +proj=cart +ellps=clrk80ign +step +proj=helmert +x=1 +y=2 " + "+z=3 +rx=4 +ry=5 +rz=6 +s=7 +convention=position_vector +step " + "+inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step " + "+proj=utm +zone=31 +ellps=WGS84"); +} + +// --------------------------------------------------------------------------- + +TEST(operation, boundCRS_of_geogCRS_to_unrelated_geogCRS_context) { + auto src = BoundCRS::createFromTOWGS84( + GeographicCRS::EPSG_4807, std::vector<double>{1, 2, 3, 4, 5, 6, 7}); + auto authFactory = + AuthorityFactory::create(DatabaseContext::create(), "EPSG"); + // ETRS89 + auto dst = authFactory->createCoordinateReferenceSystem("4258"); + auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0); + auto list = + CoordinateOperationFactory::create()->createOperations(src, dst, ctxt); + ASSERT_EQ(list.size(), 1U); + // Check with it is a concatenated operation, since it doesn't particularly + // show up in the PROJ string + EXPECT_TRUE(dynamic_cast<ConcatenatedOperation *>(list[0].get()) != + nullptr); + EXPECT_EQ(list[0]->nameStr(), "Transformation from NTF (Paris) to WGS84 + " + "Inverse of ETRS89 to WGS 84 (1)"); + EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()), + "+proj=pipeline " + "+step +proj=axisswap +order=2,1 " + "+step +proj=unitconvert +xy_in=grad +xy_out=rad " + "+step +inv +proj=longlat +ellps=clrk80ign +pm=paris " + "+step +proj=push +v_3 +step +proj=cart +ellps=clrk80ign " + "+step +proj=helmert +x=1 +y=2 +z=3 +rx=4 +ry=5 +rz=6 +s=7 " + "+convention=position_vector " + "+step +inv +proj=cart +ellps=GRS80 +step +proj=pop +v_3 " + "+step +proj=unitconvert +xy_in=rad +xy_out=deg " + "+step +proj=axisswap +order=2,1"); } // --------------------------------------------------------------------------- @@ -5501,14 +5710,14 @@ TEST(operation, geogCRS_to_boundCRS_of_geogCRS) { GeographicCRS::EPSG_4326, boundCRS); ASSERT_TRUE(op != nullptr); EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), - "+proj=pipeline +step +proj=push +v_3 +step +proj=axisswap " - "+order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step " - "+proj=cart +ellps=WGS84 +step +inv +proj=helmert +x=1 +y=2 +z=3 " - "+rx=4 +ry=5 +rz=6 +s=7 +convention=position_vector +step +inv " - "+proj=cart +ellps=clrk80ign +step +proj=longlat " - "+ellps=clrk80ign +pm=paris +step +proj=unitconvert +xy_in=rad " - "+xy_out=grad +step +proj=axisswap +order=2,1 +step +proj=pop " - "+v_3"); + "+proj=pipeline +step +proj=axisswap +order=2,1 +step " + "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 " + "+step +proj=cart +ellps=WGS84 +step +inv +proj=helmert +x=1 " + "+y=2 +z=3 +rx=4 +ry=5 +rz=6 +s=7 +convention=position_vector " + "+step +inv +proj=cart +ellps=clrk80ign +step +proj=pop +v_3 " + "+step +proj=longlat +ellps=clrk80ign +pm=paris +step " + "+proj=unitconvert +xy_in=rad +xy_out=grad +step +proj=axisswap " + "+order=2,1"); } // --------------------------------------------------------------------------- @@ -5531,14 +5740,12 @@ TEST(operation, boundCRS_to_boundCRS) { ASSERT_TRUE(op != nullptr); EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), "+proj=pipeline +step +inv +proj=utm +zone=31 +ellps=clrk80ign " - "+pm=paris +step +proj=longlat +ellps=clrk80ign +pm=paris +step " - "+proj=push +v_3 +step +inv +proj=longlat +ellps=clrk80ign " - "+pm=paris +step +proj=cart +ellps=clrk80ign +step +proj=helmert " - "+x=1 +y=2 +z=3 +rx=4 +ry=5 +rz=6 +s=7 " - "+convention=position_vector +step +inv +proj=helmert +x=8 +y=9 " - "+z=10 +rx=11 +ry=12 +rz=13 +s=14 +convention=position_vector " - "+step +inv +proj=cart +ellps=GRS80 +step +proj=pop +v_3 +step " - "+proj=utm +zone=32 +ellps=GRS80"); + "+pm=paris +step +proj=push +v_3 +step +proj=cart " + "+ellps=clrk80ign +step +proj=helmert +x=1 +y=2 +z=3 +rx=4 +ry=5 " + "+rz=6 +s=7 +convention=position_vector +step +inv +proj=helmert " + "+x=8 +y=9 +z=10 +rx=11 +ry=12 +rz=13 +s=14 " + "+convention=position_vector +step +inv +proj=cart +ellps=GRS80 " + "+step +proj=pop +v_3 +step +proj=utm +zone=32 +ellps=GRS80"); } // --------------------------------------------------------------------------- @@ -5552,12 +5759,12 @@ TEST(operation, boundCRS_to_boundCRS_noop_for_TOWGS84) { boundCRS2); ASSERT_TRUE(op != nullptr); EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), - "+proj=pipeline +step +proj=push +v_3 +step +proj=axisswap " - "+order=2,1 +step +proj=unitconvert +xy_in=grad +xy_out=rad " - "+step +inv +proj=longlat +ellps=clrk80ign +pm=paris +step " - "+proj=cart +ellps=clrk80ign +step +inv +proj=cart +ellps=GRS80 " - "+step +proj=unitconvert +xy_in=rad +xy_out=deg +step " - "+proj=axisswap +order=2,1 +step +proj=pop +v_3"); + "+proj=pipeline +step +proj=axisswap +order=2,1 +step " + "+proj=unitconvert +xy_in=grad +xy_out=rad +step +inv " + "+proj=longlat +ellps=clrk80ign +pm=paris +step +proj=push +v_3 " + "+step +proj=cart +ellps=clrk80ign +step +inv +proj=cart " + "+ellps=GRS80 +step +proj=pop +v_3 +step +proj=unitconvert " + "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1"); } // --------------------------------------------------------------------------- @@ -5696,6 +5903,35 @@ TEST(operation, boundCRS_with_basecrs_with_extent_to_geogCRS) { // --------------------------------------------------------------------------- +TEST(operation, ETRS89_3D_to_proj_string_with_geoidgrids_nadgrids) { + auto authFactory = + AuthorityFactory::create(DatabaseContext::create(), "EPSG"); + // ETRS89 3D + auto src = authFactory->createCoordinateReferenceSystem("4937"); + auto objDst = PROJStringParser().createFromPROJString( + "+proj=sterea +lat_0=52.15616055555555 +lon_0=5.38763888888889 " + "+k=0.9999079 +x_0=155000 +y_0=463000 +ellps=bessel " + "+nadgrids=rdtrans2008.gsb +geoidgrids=naptrans2008.gtx +units=m " + "+type=crs"); + auto dst = nn_dynamic_pointer_cast<CRS>(objDst); + ASSERT_TRUE(dst != nullptr); + auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0); + auto list = CoordinateOperationFactory::create()->createOperations( + src, NN_NO_CHECK(dst), ctxt); + ASSERT_EQ(list.size(), 1U); + EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()), + "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad " + "+step +proj=axisswap +order=2,1 " + "+step +inv +proj=vgridshift +grids=naptrans2008.gtx " + "+multiplier=1 " + "+step +inv +proj=hgridshift +grids=rdtrans2008.gsb " + "+step +proj=sterea +lat_0=52.1561605555556 " + "+lon_0=5.38763888888889 +k=0.9999079 +x_0=155000 " + "+y_0=463000 +ellps=bessel"); +} + +// --------------------------------------------------------------------------- + static VerticalCRSNNPtr createVerticalCRS() { PropertyMap propertiesVDatum; propertiesVDatum.set(Identifier::CODESPACE_KEY, "EPSG") @@ -5734,8 +5970,8 @@ static BoundCRSNNPtr createBoundVerticalCRS() { auto vertCRS = createVerticalCRS(); auto transformation = Transformation::createGravityRelatedHeightToGeographic3D( - PropertyMap(), vertCRS, GeographicCRS::EPSG_4979, "egm08_25.gtx", - std::vector<PositionalAccuracyNNPtr>()); + PropertyMap(), vertCRS, GeographicCRS::EPSG_4979, nullptr, + "egm08_25.gtx", std::vector<PositionalAccuracyNNPtr>()); return BoundCRS::create(vertCRS, GeographicCRS::EPSG_4979, transformation); } @@ -5769,6 +6005,59 @@ TEST(operation, transformation_height_to_PROJ_string) { // --------------------------------------------------------------------------- +TEST(operation, transformation_Geographic3D_to_GravityRelatedHeight_gtx) { + auto wkt = + "COORDINATEOPERATION[\"ETRS89 to NAP height (1)\",\n" + " VERSION[\"RDNAP-Nld 2008\"],\n" + " SOURCECRS[\n" + " GEOGCRS[\"ETRS89\",\n" + " DATUM[\"European Terrestrial Reference System 1989\",\n" + " ELLIPSOID[\"GRS 1980\",6378137,298.257222101,\n" + " LENGTHUNIT[\"metre\",1]]],\n" + " PRIMEM[\"Greenwich\",0,\n" + " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" + " CS[ellipsoidal,3],\n" + " AXIS[\"geodetic latitude (Lat)\",north,\n" + " ORDER[1],\n" + " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" + " AXIS[\"geodetic longitude (Lon)\",east,\n" + " ORDER[2],\n" + " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" + " AXIS[\"ellipsoidal height (h)\",up,\n" + " ORDER[3],\n" + " LENGTHUNIT[\"metre\",1]],\n" + " ID[\"EPSG\",4937]]],\n" + " TARGETCRS[\n" + " VERTCRS[\"NAP height\",\n" + " VDATUM[\"Normaal Amsterdams Peil\"],\n" + " CS[vertical,1],\n" + " AXIS[\"gravity-related height (H)\",up,\n" + " LENGTHUNIT[\"metre\",1]],\n" + " ID[\"EPSG\",5709]]],\n" + " METHOD[\"Geographic3D to GravityRelatedHeight (US .gtx)\",\n" + " ID[\"EPSG\",9665]],\n" + " PARAMETERFILE[\"Geoid (height correction) model " + "file\",\"naptrans2008.gtx\"],\n" + " OPERATIONACCURACY[0.01],\n" + " USAGE[\n" + " SCOPE[\"unknown\"],\n" + " AREA[\"Netherlands - onshore\"],\n" + " BBOX[50.75,3.2,53.7,7.22]],\n" + " ID[\"EPSG\",7001]]"; + ; + auto obj = WKTParser().createFromWKT(wkt); + auto transf = nn_dynamic_pointer_cast<Transformation>(obj); + ASSERT_TRUE(transf != nullptr); + + // Check that we correctly inverse files in the case of + // "Geographic3D to GravityRelatedHeight (US .gtx)" + EXPECT_EQ(transf->exportToPROJString(PROJStringFormatter::create().get()), + "+proj=pipeline +step +inv +proj=vgridshift " + "+grids=naptrans2008.gtx +multiplier=1"); +} + +// --------------------------------------------------------------------------- + TEST(operation, transformation_ntv2_to_PROJ_string) { auto transformation = Transformation::createNTv2( PropertyMap(), GeographicCRS::EPSG_4807, GeographicCRS::EPSG_4326, @@ -5955,13 +6244,13 @@ TEST(operation, compoundCRS_with_boundGeogCRS_to_geogCRS) { compound, GeographicCRS::EPSG_4979); ASSERT_TRUE(op != nullptr); EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), - "+proj=pipeline +step +proj=push +v_3 +step +proj=axisswap " - "+order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step " - "+proj=cart +ellps=WGS84 +step +proj=helmert +x=1 +y=2 +z=3 " - "+rx=4 +ry=5 +rz=6 +s=7 +convention=position_vector +step +inv " - "+proj=cart +ellps=WGS84 +step +proj=unitconvert +xy_in=rad " - "+xy_out=deg +step +proj=axisswap +order=2,1 +step +proj=pop " - "+v_3"); + "+proj=pipeline +step +proj=axisswap +order=2,1 +step " + "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 " + "+step +proj=cart +ellps=WGS84 +step +proj=helmert +x=1 +y=2 " + "+z=3 +rx=4 +ry=5 +rz=6 +s=7 +convention=position_vector +step " + "+inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step " + "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap " + "+order=2,1"); } // --------------------------------------------------------------------------- @@ -5979,12 +6268,12 @@ TEST(operation, compoundCRS_with_boundGeogCRS_and_boundVerticalCRS_to_geogCRS) { // Not completely sure the order of horizontal and vertical operations // makes sense EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), - "+proj=pipeline +step +proj=push +v_3 +step +proj=axisswap " - "+order=2,1 +step +proj=unitconvert +xy_in=grad +xy_out=rad " - "+step +inv +proj=longlat +ellps=clrk80ign +pm=paris +step " - "+proj=cart +ellps=clrk80ign +step +proj=helmert +x=1 +y=2 +z=3 " - "+rx=4 +ry=5 +rz=6 +s=7 +convention=position_vector +step +inv " - "+proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step " + "+proj=pipeline +step +proj=axisswap +order=2,1 +step " + "+proj=unitconvert +xy_in=grad +xy_out=rad +step +inv " + "+proj=longlat +ellps=clrk80ign +pm=paris +step +proj=push +v_3 " + "+step +proj=cart +ellps=clrk80ign +step +proj=helmert +x=1 +y=2 " + "+z=3 +rx=4 +ry=5 +rz=6 +s=7 +convention=position_vector +step " + "+inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step " "+proj=vgridshift +grids=egm08_25.gtx +multiplier=1 +step " "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap " "+order=2,1"); @@ -6018,14 +6307,12 @@ TEST(operation, compoundCRS_with_boundProjCRS_and_boundVerticalCRS_to_geogCRS) { // makes sense EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), "+proj=pipeline +step +inv +proj=utm +zone=31 +ellps=clrk80ign " - "+pm=paris +step +proj=longlat +ellps=clrk80ign +pm=paris +step " - "+proj=push +v_3 +step +inv +proj=longlat +ellps=clrk80ign " - "+pm=paris +step +proj=cart +ellps=clrk80ign +step +proj=helmert " - "+x=1 +y=2 +z=3 +rx=4 +ry=5 +rz=6 +s=7 " - "+convention=position_vector +step +inv +proj=cart +ellps=WGS84 " - "+step +proj=pop +v_3 +step +proj=vgridshift +grids=egm08_25.gtx " - "+multiplier=1 +step +proj=unitconvert +xy_in=rad +xy_out=deg " - "+step +proj=axisswap +order=2,1"); + "+pm=paris +step +proj=push +v_3 +step +proj=cart " + "+ellps=clrk80ign +step +proj=helmert +x=1 +y=2 +z=3 +rx=4 +ry=5 " + "+rz=6 +s=7 +convention=position_vector +step +inv +proj=cart " + "+ellps=WGS84 +step +proj=pop +v_3 +step +proj=vgridshift " + "+grids=egm08_25.gtx +multiplier=1 +step +proj=unitconvert " + "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1"); auto opInverse = CoordinateOperationFactory::create()->createOperation( GeographicCRS::EPSG_4979, compound); @@ -6035,6 +6322,51 @@ TEST(operation, compoundCRS_with_boundProjCRS_and_boundVerticalCRS_to_geogCRS) { // --------------------------------------------------------------------------- +TEST(operation, geocent_to_compoundCRS) { + auto objSrc = PROJStringParser().createFromPROJString( + "+proj=geocent +datum=WGS84 +units=m +type=crs"); + auto src = nn_dynamic_pointer_cast<CRS>(objSrc); + ASSERT_TRUE(src != nullptr); + auto objDst = PROJStringParser().createFromPROJString( + "+proj=longlat +ellps=GRS67 +nadgrids=@foo.gsb +geoidgrids=@foo.gtx " + "+type=crs"); + auto dst = nn_dynamic_pointer_cast<CRS>(objDst); + ASSERT_TRUE(dst != nullptr); + auto op = CoordinateOperationFactory::create()->createOperation( + NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst)); + ASSERT_TRUE(op != nullptr); + EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), + "+proj=pipeline +step +inv +proj=cart +ellps=WGS84 +step +inv " + "+proj=vgridshift +grids=@foo.gtx +multiplier=1 +step +inv " + "+proj=hgridshift +grids=@foo.gsb +step +proj=unitconvert " + "+xy_in=rad +xy_out=deg"); +} + +// --------------------------------------------------------------------------- + +TEST(operation, geocent_to_compoundCRS_context) { + auto authFactory = + AuthorityFactory::create(DatabaseContext::create(), "EPSG"); + // WGS84 geocentric + auto src = authFactory->createCoordinateReferenceSystem("4978"); + auto objDst = PROJStringParser().createFromPROJString( + "+proj=longlat +ellps=GRS67 +nadgrids=@foo.gsb +geoidgrids=@foo.gtx " + "+type=crs"); + auto dst = nn_dynamic_pointer_cast<CRS>(objDst); + ASSERT_TRUE(dst != nullptr); + auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0); + auto list = CoordinateOperationFactory::create()->createOperations( + src, NN_CHECK_ASSERT(dst), ctxt); + ASSERT_EQ(list.size(), 1U); + EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()), + "+proj=pipeline +step +inv +proj=cart +ellps=WGS84 +step +inv " + "+proj=vgridshift +grids=@foo.gtx +multiplier=1 +step +inv " + "+proj=hgridshift +grids=@foo.gsb +step +proj=unitconvert " + "+xy_in=rad +xy_out=deg"); +} + +// --------------------------------------------------------------------------- + TEST(operation, compoundCRS_to_compoundCRS) { auto compound1 = CompoundCRS::create( PropertyMap(), @@ -6125,6 +6457,100 @@ TEST(operation, compoundCRS_to_compoundCRS_with_vertical_transform) { // --------------------------------------------------------------------------- +TEST(operation, compoundCRS_to_compoundCRS_with_bound_crs_in_horiz_and_vert) { + auto objSrc = PROJStringParser().createFromPROJString( + "+proj=longlat +ellps=GRS67 +nadgrids=@foo.gsb +geoidgrids=@foo.gtx " + "+type=crs"); + auto src = nn_dynamic_pointer_cast<CRS>(objSrc); + ASSERT_TRUE(src != nullptr); + auto objDst = PROJStringParser().createFromPROJString( + "+proj=longlat +ellps=GRS80 +nadgrids=@bar.gsb +geoidgrids=@bar.gtx " + "+type=crs"); + auto dst = nn_dynamic_pointer_cast<CRS>(objDst); + ASSERT_TRUE(dst != nullptr); + auto op = CoordinateOperationFactory::create()->createOperation( + NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst)); + ASSERT_TRUE(op != nullptr); + EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), + "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad " + "+step +proj=hgridshift +grids=@foo.gsb " + "+step +proj=vgridshift +grids=@foo.gtx +multiplier=1 " + "+step +inv +proj=vgridshift +grids=@bar.gtx +multiplier=1 " + "+step +inv +proj=hgridshift +grids=@bar.gsb " + "+step +proj=unitconvert +xy_in=rad +xy_out=deg"); +} + +// --------------------------------------------------------------------------- + +TEST(operation, compoundCRS_to_compoundCRS_context) { + auto authFactory = + AuthorityFactory::create(DatabaseContext::create(), "EPSG"); + auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0); + ctxt->setSpatialCriterion( + CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION); + auto list = CoordinateOperationFactory::create()->createOperations( + // NAD27 + NGVD29 height (ftUS) + authFactory->createCoordinateReferenceSystem("7406"), + // NAD83(NSRS2007) + NAVD88 height + authFactory->createCoordinateReferenceSystem("5500"), ctxt); + // 152 or 155 depending if the VERTCON grids are there + ASSERT_GE(list.size(), 152U); + EXPECT_FALSE(list[0]->hasBallparkTransformation()); + EXPECT_EQ(list[0]->nameStr(), "NGVD29 height (ftUS) to NAVD88 height (3) + " + "NAD27 to WGS 84 (79) + Inverse of " + "NAD83(NSRS2007) to WGS 84 (1)"); + EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()), + "+proj=pipeline +step +proj=axisswap +order=2,1 +step " + "+proj=unitconvert +xy_in=deg +z_in=us-ft +xy_out=rad +z_out=m " + "+step +proj=vgridshift +grids=vertcone.gtx +multiplier=0.001 " + "+step +proj=hgridshift +grids=conus +step " + "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap " + "+order=2,1"); + { + // Test that we can round-trip this through WKT and still get the same + // PROJ string. + auto wkt = list[0]->exportToWKT( + WKTFormatter::create(WKTFormatter::Convention::WKT2_2018).get()); + auto obj = WKTParser().createFromWKT(wkt); + auto co = nn_dynamic_pointer_cast<CoordinateOperation>(obj); + ASSERT_TRUE(co != nullptr); + EXPECT_EQ( + list[0]->exportToPROJString(PROJStringFormatter::create().get()), + co->exportToPROJString(PROJStringFormatter::create().get())); + } + + bool foundApprox = false; + for (size_t i = 0; i < list.size(); i++) { + auto projString = + list[i]->exportToPROJString(PROJStringFormatter::create().get()); + EXPECT_TRUE( + projString.find("+proj=pipeline +step +proj=axisswap +order=2,1 " + "+step +proj=unitconvert +xy_in=deg +z_in=us-ft " + "+xy_out=rad +z_out=m") == 0) + << list[i]->nameStr(); + if (list[i]->nameStr().find("Transformation from NGVD29 height (ftUS) " + "to NAVD88 height (ballpark vertical " + "transformation)") == 0) { + EXPECT_TRUE(list[i]->hasBallparkTransformation()); + EXPECT_EQ(list[i]->nameStr(), + "Transformation from NGVD29 height (ftUS) to NAVD88 " + "height (ballpark vertical transformation) + NAD27 to " + "WGS 84 (79) + Inverse of NAD83(NSRS2007) to WGS 84 (1)"); + EXPECT_EQ(projString, + "+proj=pipeline +step +proj=axisswap +order=2,1 +step " + "+proj=unitconvert +xy_in=deg +z_in=us-ft +xy_out=rad " + "+z_out=m +step +proj=hgridshift +grids=conus " + "+step +proj=unitconvert +xy_in=rad " + "+xy_out=deg +step +proj=axisswap +order=2,1"); + foundApprox = true; + break; + } + } + EXPECT_TRUE(foundApprox); +} + +// --------------------------------------------------------------------------- + TEST(operation, vertCRS_to_vertCRS) { auto vertcrs_m_obj = PROJStringParser().createFromPROJString("+vunits=m"); @@ -6174,6 +6600,25 @@ TEST(operation, vertCRS_to_vertCRS) { // --------------------------------------------------------------------------- +TEST(operation, vertCRS_to_vertCRS_context) { + auto authFactory = + AuthorityFactory::create(DatabaseContext::create(), "EPSG"); + auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0); + ctxt->setSpatialCriterion( + CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION); + auto list = CoordinateOperationFactory::create()->createOperations( + // NGVD29 height (m) + authFactory->createCoordinateReferenceSystem("7968"), + // NAVD88 height (1) + authFactory->createCoordinateReferenceSystem("5703"), ctxt); + ASSERT_EQ(list.size(), 3U); + EXPECT_EQ(list[0]->nameStr(), "NGVD29 height (m) to NAVD88 height (3)"); + EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()), + "+proj=vgridshift +grids=vertcone.gtx +multiplier=0.001"); +} + +// --------------------------------------------------------------------------- + TEST(operation, compoundCRS_to_geogCRS_3D) { auto compoundcrs_ft_obj = PROJStringParser().createFromPROJString( @@ -6190,6 +6635,7 @@ TEST(operation, compoundCRS_to_geogCRS_3D) { auto op = CoordinateOperationFactory::create()->createOperation( NN_CHECK_ASSERT(compoundcrs_ft), NN_CHECK_ASSERT(geogcrs_m)); ASSERT_TRUE(op != nullptr); + EXPECT_TRUE(op->hasBallparkTransformation()); EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), "+proj=pipeline +step +inv +proj=merc +lon_0=0 +k=1 +x_0=0 " "+y_0=0 +ellps=WGS84 +step +proj=unitconvert +xy_in=rad " @@ -6200,6 +6646,7 @@ TEST(operation, compoundCRS_to_geogCRS_3D) { auto op = CoordinateOperationFactory::create()->createOperation( NN_CHECK_ASSERT(geogcrs_m), NN_CHECK_ASSERT(compoundcrs_ft)); ASSERT_TRUE(op != nullptr); + EXPECT_TRUE(op->hasBallparkTransformation()); EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), "+proj=pipeline +step +proj=unitconvert +xy_in=deg +z_in=m " "+xy_out=rad +z_out=ft +step +proj=merc +lon_0=0 +k=1 +x_0=0 " @@ -6209,6 +6656,195 @@ TEST(operation, compoundCRS_to_geogCRS_3D) { // --------------------------------------------------------------------------- +TEST(operation, compoundCRS_to_geogCRS_3D_context) { + auto authFactory = + AuthorityFactory::create(DatabaseContext::create(), "EPSG"); + // CompoundCRS to Geog3DCRS, with vertical unit change, but without + // ellipsoid height <--> vertical height correction + { + auto ctxt = + CoordinateOperationContext::create(authFactory, nullptr, 0.0); + auto list = CoordinateOperationFactory::create()->createOperations( + authFactory->createCoordinateReferenceSystem( + "7406"), // NAD27 + NGVD29 height (ftUS) + authFactory->createCoordinateReferenceSystem("4979"), // WGS 84 + ctxt); + ASSERT_GE(list.size(), 1U); + EXPECT_TRUE(list[0]->hasBallparkTransformation()); + EXPECT_EQ(list[0]->nameStr(), + "NAD27 to WGS 84 (79) + Transformation from NGVD29 height " + "(ftUS) to WGS 84 (ballpark vertical transformation, without " + "ellipsoid height to vertical height correction)"); + EXPECT_EQ(list[0]->exportToPROJString( + PROJStringFormatter::create( + PROJStringFormatter::Convention::PROJ_5, + authFactory->databaseContext()) + .get()), + "+proj=pipeline +step +proj=axisswap +order=2,1 +step " + "+proj=unitconvert +xy_in=deg +xy_out=rad +step " + "+proj=hgridshift +grids=conus +step +proj=unitconvert " + "+xy_in=rad +z_in=us-ft +xy_out=deg +z_out=m +step " + "+proj=axisswap +order=2,1"); + } + + // CompoundCRS to Geog3DCRS, with same vertical unit, but without + // ellipsoid height <--> vertical height correction + { + auto ctxt = + CoordinateOperationContext::create(authFactory, nullptr, 0.0); + auto list = CoordinateOperationFactory::create()->createOperations( + authFactory->createCoordinateReferenceSystem( + "5500"), // NAD83(NSRS2007) + NAVD88 height + authFactory->createCoordinateReferenceSystem("4979"), // WGS 84 + ctxt); + ASSERT_GE(list.size(), 1U); + EXPECT_TRUE(list[0]->hasBallparkTransformation()); + EXPECT_EQ(list[0]->nameStr(), + "NAD83(NSRS2007) to WGS 84 (1) + Transformation from NAVD88 " + "height to WGS 84 (ballpark vertical transformation, without " + "ellipsoid height to vertical height correction)"); + EXPECT_EQ(list[0]->exportToPROJString( + PROJStringFormatter::create( + PROJStringFormatter::Convention::PROJ_5, + authFactory->databaseContext()) + .get()), + "+proj=noop"); + } +} + +// --------------------------------------------------------------------------- + +TEST(operation, compoundCRS_from_WKT2_to_geogCRS_3D_context) { + auto authFactory = + AuthorityFactory::create(DatabaseContext::create(), "EPSG"); + auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0); + auto src = authFactory->createCoordinateReferenceSystem( + "7415"); // Amersfoort / RD New + NAP height + auto dst = + authFactory->createCoordinateReferenceSystem("4937"); // ETRS89 3D + auto list = + CoordinateOperationFactory::create()->createOperations(src, dst, ctxt); + ASSERT_GE(list.size(), 1U); + auto wkt2 = src->exportToWKT( + WKTFormatter::create(WKTFormatter::Convention::WKT2_2018).get()); + auto obj = WKTParser().createFromWKT(wkt2); + auto src_from_wkt2 = nn_dynamic_pointer_cast<CRS>(obj); + ASSERT_TRUE(src_from_wkt2 != nullptr); + auto list2 = CoordinateOperationFactory::create()->createOperations( + NN_NO_CHECK(src_from_wkt2), dst, ctxt); + ASSERT_GE(list.size(), list2.size()); + for (size_t i = 0; i < list.size(); i++) { + const auto &op = list[i]; + const auto &op2 = list2[i]; + EXPECT_TRUE( + op->isEquivalentTo(op2.get(), IComparable::Criterion::EQUIVALENT)); + } +} + +// --------------------------------------------------------------------------- + +TEST(operation, compoundCRS_from_WKT2_no_id_to_geogCRS_3D_context) { + auto authFactory = + AuthorityFactory::create(DatabaseContext::create(), "EPSG"); + auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0); + ctxt->setSpatialCriterion( + CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION); + auto src = authFactory->createCoordinateReferenceSystem( + "7415"); // Amersfoort / RD New + NAP height + auto dst = + authFactory->createCoordinateReferenceSystem("4937"); // ETRS89 3D + auto list = + CoordinateOperationFactory::create()->createOperations(src, dst, ctxt); + ASSERT_GE(list.size(), 1U); + + { + // Important here is vgridshift before hgridshift + auto op_proj = + list[0]->exportToPROJString(PROJStringFormatter::create().get()); + EXPECT_EQ( + op_proj, + "+proj=pipeline +step +inv +proj=sterea +lat_0=52.1561605555556 " + "+lon_0=5.38763888888889 +k=0.9999079 +x_0=155000 +y_0=463000 " + "+ellps=bessel " + "+step +proj=vgridshift +grids=naptrans2008.gtx +multiplier=1 " + "+step +proj=hgridshift +grids=rdtrans2008.gsb " + "+step +proj=unitconvert +xy_in=rad +z_in=m +xy_out=deg +z_out=m " + "+step +proj=axisswap +order=2,1"); + } + + auto wkt2 = + "COMPOUNDCRS[\"unknown\",\n" + " PROJCRS[\"unknown\",\n" + " BASEGEOGCRS[\"Amersfoort\",\n" + " DATUM[\"Amersfoort\",\n" + " ELLIPSOID[\"Bessel " + "1841\",6377397.155,299.1528128]]],\n" + " CONVERSION[\"unknown\",\n" + " METHOD[\"Oblique Stereographic\"],\n" + " PARAMETER[\"Latitude of natural origin\",52.1561605555556],\n" + " PARAMETER[\"Longitude of natural origin\",5.38763888888889],\n" + " PARAMETER[\"Scale factor at natural origin\",0.9999079],\n" + " PARAMETER[\"False easting\",155000],\n" + " PARAMETER[\"False northing\",463000]],\n" + " CS[Cartesian,2],\n" + " AXIS[\"(E)\",east],\n" + " AXIS[\"(N)\",north],\n" + " LENGTHUNIT[\"metre\",1]],\n" + " VERTCRS[\"NAP height\",\n" + " VDATUM[\"Normaal Amsterdams Peil\"],\n" + " CS[vertical,1],\n" + " AXIS[\"gravity-related height (H)\",up,\n" + " LENGTHUNIT[\"metre\",1]]]]"; + auto obj = WKTParser().createFromWKT(wkt2); + auto src_from_wkt2 = nn_dynamic_pointer_cast<CRS>(obj); + ASSERT_TRUE(src_from_wkt2 != nullptr); + auto list2 = CoordinateOperationFactory::create()->createOperations( + NN_NO_CHECK(src_from_wkt2), dst, ctxt); + ASSERT_GE(list.size(), list2.size() - 1); + for (size_t i = 0; i < list.size(); i++) { + const auto &op = list[i]; + const auto &op2 = list2[i]; + auto op_proj = + op->exportToPROJString(PROJStringFormatter::create().get()); + auto op2_proj = + op2->exportToPROJString(PROJStringFormatter::create().get()); + EXPECT_EQ(op_proj, op2_proj) << "op=" << op->nameStr() + << " op2=" << op2->nameStr(); + } +} + +// --------------------------------------------------------------------------- + +TEST(operation, boundCRS_to_compoundCRS) { + auto objSrc = PROJStringParser().createFromPROJString( + "+proj=longlat +ellps=GRS67 +nadgrids=@foo.gsb +type=crs"); + auto src = nn_dynamic_pointer_cast<CRS>(objSrc); + ASSERT_TRUE(src != nullptr); + auto objDst = PROJStringParser().createFromPROJString( + "+proj=longlat +ellps=GRS80 +nadgrids=@bar.gsb +geoidgrids=@bar.gtx " + "+type=crs"); + auto dst = nn_dynamic_pointer_cast<CRS>(objDst); + ASSERT_TRUE(dst != nullptr); + + auto op = CoordinateOperationFactory::create()->createOperation( + NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst)); + ASSERT_TRUE(op != nullptr); + EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), + "+proj=pipeline " + "+step +proj=unitconvert +xy_in=deg +xy_out=rad " + "+step +proj=hgridshift +grids=@foo.gsb " + "+step +inv +proj=vgridshift +grids=@bar.gtx +multiplier=1 " + "+step +inv +proj=hgridshift +grids=@bar.gsb " + "+step +proj=unitconvert +xy_in=rad +xy_out=deg"); + + auto opInverse = CoordinateOperationFactory::create()->createOperation( + NN_CHECK_ASSERT(dst), NN_CHECK_ASSERT(src)); + ASSERT_TRUE(opInverse != nullptr); + EXPECT_TRUE(opInverse->inverse()->_isEquivalentTo(op.get())); +} + +// --------------------------------------------------------------------------- + TEST(operation, IGNF_LAMB1_TO_EPSG_4326) { auto authFactory = AuthorityFactory::create(DatabaseContext::create(), std::string()); @@ -6223,6 +6859,7 @@ TEST(operation, IGNF_LAMB1_TO_EPSG_4326) { ctxt); ASSERT_EQ(list.size(), 2U); + EXPECT_FALSE(list[0]->hasBallparkTransformation()); EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()), "+proj=pipeline +step +inv +proj=lcc +lat_1=49.5 +lat_0=49.5 " "+lon_0=0 +k_0=0.99987734 +x_0=600000 +y_0=200000 " @@ -6230,14 +6867,15 @@ TEST(operation, IGNF_LAMB1_TO_EPSG_4326) { "+grids=ntf_r93.gsb +step +proj=unitconvert +xy_in=rad " "+xy_out=deg +step +proj=axisswap +order=2,1"); + EXPECT_FALSE(list[1]->hasBallparkTransformation()); EXPECT_EQ(list[1]->exportToPROJString(PROJStringFormatter::create().get()), "+proj=pipeline +step +inv +proj=lcc +lat_1=49.5 +lat_0=49.5 " "+lon_0=0 +k_0=0.99987734 +x_0=600000 +y_0=200000 " "+ellps=clrk80ign +pm=paris +step +proj=push +v_3 +step " "+proj=cart +ellps=clrk80ign +step +proj=helmert +x=-168 +y=-60 " - "+z=320 +step +inv +proj=cart +ellps=WGS84 +step " - "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap " - "+order=2,1 +step +proj=pop +v_3"); + "+z=320 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 " + "+step +proj=unitconvert +xy_in=rad +xy_out=deg +step " + "+proj=axisswap +order=2,1"); auto list2 = CoordinateOperationFactory::create()->createOperations( AuthorityFactory::create(DatabaseContext::create(), "EPSG") @@ -6264,14 +6902,14 @@ TEST(operation, IGNF_LAMB1_TO_EPSG_4326) { // --------------------------------------------------------------------------- -TEST(operation, isPROJInstanciable) { +TEST(operation, isPROJInstantiable) { { auto transformation = Transformation::createGeocentricTranslations( PropertyMap(), GeographicCRS::EPSG_4269, GeographicCRS::EPSG_4326, 1.0, 2.0, 3.0, {}); EXPECT_TRUE( - transformation->isPROJInstanciable(DatabaseContext::create())); + transformation->isPROJInstantiable(DatabaseContext::create())); } // Missing grid @@ -6280,7 +6918,7 @@ TEST(operation, isPROJInstanciable) { PropertyMap(), GeographicCRS::EPSG_4807, GeographicCRS::EPSG_4326, "foo.gsb", std::vector<PositionalAccuracyNNPtr>()); EXPECT_FALSE( - transformation->isPROJInstanciable(DatabaseContext::create())); + transformation->isPROJInstantiable(DatabaseContext::create())); } // Unsupported method @@ -6292,7 +6930,7 @@ TEST(operation, isPROJInstanciable) { std::vector<GeneralParameterValueNNPtr>{}, std::vector<PositionalAccuracyNNPtr>{}); EXPECT_FALSE( - transformation->isPROJInstanciable(DatabaseContext::create())); + transformation->isPROJInstantiable(DatabaseContext::create())); } } @@ -7370,3 +8008,123 @@ TEST(operation, validateParameters) { EXPECT_EQ(validation, expected); } } + +// --------------------------------------------------------------------------- + +TEST(operation, normalizeForVisualization) { + + auto authFactory = + AuthorityFactory::create(DatabaseContext::create(), "EPSG"); + + // Source(geographic) must be inverted + { + auto src = authFactory->createCoordinateReferenceSystem("4326"); + auto dst = authFactory->createCoordinateReferenceSystem("32631"); + auto op = + CoordinateOperationFactory::create()->createOperation(src, dst); + ASSERT_TRUE(op != nullptr); + auto opNormalized = op->normalizeForVisualization(); + EXPECT_FALSE(opNormalized->_isEquivalentTo(op.get())); + EXPECT_EQ(opNormalized->exportToPROJString( + PROJStringFormatter::create().get()), + "+proj=pipeline " + "+step +proj=unitconvert +xy_in=deg +xy_out=rad " + "+step +proj=utm +zone=31 +ellps=WGS84"); + } + + // Target(geographic) must be inverted + { + auto src = authFactory->createCoordinateReferenceSystem("32631"); + auto dst = authFactory->createCoordinateReferenceSystem("4326"); + auto op = + CoordinateOperationFactory::create()->createOperation(src, dst); + ASSERT_TRUE(op != nullptr); + auto opNormalized = op->normalizeForVisualization(); + EXPECT_FALSE(opNormalized->_isEquivalentTo(op.get())); + EXPECT_EQ(opNormalized->exportToPROJString( + PROJStringFormatter::create().get()), + "+proj=pipeline " + "+step +inv +proj=utm +zone=31 +ellps=WGS84 " + "+step +proj=unitconvert +xy_in=rad +xy_out=deg"); + } + + // Source(geographic) and target(projected) must be inverted + { + auto src = authFactory->createCoordinateReferenceSystem("4326"); + auto dst = authFactory->createCoordinateReferenceSystem("3040"); + auto op = + CoordinateOperationFactory::create()->createOperation(src, dst); + ASSERT_TRUE(op != nullptr); + auto opNormalized = op->normalizeForVisualization(); + EXPECT_FALSE(opNormalized->_isEquivalentTo(op.get())); + EXPECT_EQ(opNormalized->exportToPROJString( + PROJStringFormatter::create().get()), + "+proj=pipeline " + "+step +proj=unitconvert +xy_in=deg +xy_out=rad " + "+step +proj=utm +zone=28 +ellps=GRS80"); + } + + // No inversion + { + auto src = authFactory->createCoordinateReferenceSystem("32631"); + auto dst = authFactory->createCoordinateReferenceSystem("32632"); + auto op = + CoordinateOperationFactory::create()->createOperation(src, dst); + ASSERT_TRUE(op != nullptr); + auto opNormalized = op->normalizeForVisualization(); + EXPECT_TRUE(opNormalized->_isEquivalentTo(op.get())); + } + + // Source(compoundCRS) and target(geographic 3D) must be inverted + { + auto ctxt = + CoordinateOperationContext::create(authFactory, nullptr, 0.0); + ctxt->setUsePROJAlternativeGridNames(false); + auto src = CompoundCRS::create( + PropertyMap(), + std::vector<CRSNNPtr>{ + authFactory->createCoordinateReferenceSystem("4326"), + // EGM2008 height + authFactory->createCoordinateReferenceSystem("3855")}); + auto list = CoordinateOperationFactory::create()->createOperations( + src, + authFactory->createCoordinateReferenceSystem("4979"), // WGS 84 3D + ctxt); + ASSERT_EQ(list.size(), 2U); + auto op = list[1]; + auto opNormalized = op->normalizeForVisualization(); + EXPECT_FALSE(opNormalized->_isEquivalentTo(op.get())); + EXPECT_EQ(opNormalized->exportToPROJString( + PROJStringFormatter::create( + PROJStringFormatter::Convention::PROJ_5, + authFactory->databaseContext()) + .get()), + "+proj=pipeline " + "+step +proj=unitconvert +xy_in=deg +xy_out=rad " + "+step +proj=vgridshift +grids=egm08_25.gtx +multiplier=1 " + "+step +proj=unitconvert +xy_in=rad +xy_out=deg"); + } + + // Source(boundCRS) and target(geographic) must be inverted + { + auto src = BoundCRS::createFromTOWGS84( + GeographicCRS::EPSG_4269, std::vector<double>{1, 2, 3, 4, 5, 6, 7}); + auto dst = authFactory->createCoordinateReferenceSystem("4326"); + auto op = + CoordinateOperationFactory::create()->createOperation(src, dst); + ASSERT_TRUE(op != nullptr); + auto opNormalized = op->normalizeForVisualization(); + EXPECT_FALSE(opNormalized->_isEquivalentTo(op.get())); + EXPECT_EQ(opNormalized->exportToPROJString( + PROJStringFormatter::create().get()), + "+proj=pipeline " + "+step +proj=unitconvert +xy_in=deg +xy_out=rad " + "+step +proj=push +v_3 " + "+step +proj=cart +ellps=GRS80 " + "+step +proj=helmert +x=1 +y=2 +z=3 +rx=4 +ry=5 +rz=6 +s=7 " + "+convention=position_vector " + "+step +inv +proj=cart +ellps=WGS84 " + "+step +proj=pop +v_3 " + "+step +proj=unitconvert +xy_in=rad +xy_out=deg"); + } +} |
